1

如果我试图读取多个大文件并使用密钥加入它们,我应该采取什么方法。可能有 1 到多个组合,因此一次读取一行适用于我的简单场景。寻求一些指导。谢谢!

use strict;
use warnings;

open my $head, $ARGV[0] or die "Can't open $ARGV[0] for reading: $!";
open my $addr, $ARGV[1] or die "Can't open $ARGV[1] for reading: $!";
open my $phone, $ARGV[2] or die "Can't open $ARGV[2] for reading: $!";
#open my $final, $ARGV[3] or die "Can't open $ARGV[3] for reading: $!";


while( my $line1 = <$head> and my $line2 = <$addr> and my $line3 = <$phone>)
{
        #split files to fields
        my @headValues = split('\|', $line1);

        my @addrValues = split('\|', $line2);

        my @phoneValues = split('\|', $line3);


        # if the key matches, join them
        if($headValues[0]==$addrValues[0] and $headValues[0]==$phoneValues[0])
        {

        print "$headValues[0]|$headValues[1]|$headValues[2]|$addrValues[1]|$addrValues[2]|$phoneValues[1]";

        }

}
close $head;
4

3 回答 3

2

我不确定它是否正是您正在寻找的,但您是否尝试过 UNIX 命令join?考虑这两个文件:

x.tsv

001 X1
002 X2
004 X4

y.tsv

002 Y2
003 Y3
004 Y4

该命令join x.tsv y.tsv产生:

002 X2 Y2
004 X4 Y4

也就是说,它将具有相同 ID 的行合并并丢弃其他行(为了简单起见)。

于 2013-11-05T16:24:26.987 回答
0

试图了解您的文件。你有一个值文件(不管是什么),一个文件是电话号码,一个文件是地址。那是对的吗?每个文件可以有多个headaddressphone numbers,并且每个文件都以某种方式相互对应。

您能否举例说明文件中的数据,以及它们之间的关系?一旦我更好地了解您的数据的实际外观,我会立即更新我的答案。

同时,是时候学习参考了。引用允许您创建更复杂的数据结构。而且,一旦你理解了引用,你就可以转向面向对象的 Perl,这将真正让你处理你不知道可能的编程任务。

Perl 引用允许你拥有hashes 的 hashesarrays of arraysarrays of hasheshashes of arrays,当然这些数组或 hashes 在那个数组或 hash 中本身可以有数组或 hashes。也许一个例子会有所帮助。

假设您有一个按员工编号分配的人员哈希。我假设您的第一个文件是employee_id|name,第二个文件是address|city_state,第三个是home_phone|work_phone

首先,只需将文件读入数组:

use strict;
use warnings;
use autodie;
use feature qw(say);

open my $heading_fh, "<", $file1;
open my $address_fh, "<", $file2;
open my $phone_fh, "<", $file3;

my @headings = <$heading_fh>;
chomp @headings;
close $heading_fh;

my @addresses = <$address_fh>;
chomp @addresses;
close $address_fh;

my @phones = <$phone_fh>;
chomp @phones;
close $phone_fh;

这将使操作各种数据流变得更加容易。现在,我们可以遍历每一行:

my %employees;
for my $employee_number (0..$#headings) {
    my ( $employee_id, $employee_name ) = split /\s*\|\s*/, $employees[$employee_number];
    my ( $address, $city ) = split  /\s*\|\s*/, $phones[$employee_number];
    my ( $work_phone, $home_phone ) = split /\s*\|\s*/, $addresses[$employee_number];
    my $employees{$employee_id}->{NAME} = $employee_name;
    my $employees{$employee_id}->{ADDRESS} = $address;
    my $employess{$employee_id}->{CITY} = $city;
    my $employees{$employee_id}->{WORK} = $work_phone;
    my $employees{$employee_id}->{HOME} = $home_phone;
}

现在,您有一个%employees由 键控的名为$employee_id的散列,散列中的每个条目都是对另一个散列的引用。你有一个hashes

%employees最终结果是由 键控的单个数据结构(您的) $employee_id,但每个字段都可以单独访问。员工编号 A103 的名称是什么?,它是$employees{A103}->{NAME}

代码远未完成。例如,您可能想验证所有初始数组的大小是否相同,如果不是,则死亡:

if ( ( not $#employees == $#phones ) or ( not $#employees == $#addresses ) ) {
    die qq(The files don't have the same number of entries);
}

我希望使用引用和使用更复杂的数据结构的想法可以让事情变得更容易处理。但是,如果您需要更多帮助。发布一个示例,说明您的数据是什么样的。还要解释各个领域是什么以及它们如何相互关联。

Stackoverflow上有很多帖子对我来说是这样的:

我的数据如下所示:

ajdjadd|oieuqweoqwe|qwoeqwe|(asdad|asdads)|adsadsnrrd|hqweqwe

而且,我需要让它看起来像这样:

@#*()#&&###|@#*@#&)(*&!@!|@#@#&(*&@#
于 2013-11-05T15:56:29.100 回答
0

如果我是你,那么我会从这三个文件构建一个 sqlite 数据库,然后使用 sql 来检索结果会容易得多。

我不知道它会有多快,但我认为它比并行读取三个文件要强大得多。SQlite 可以处理这么多的数据。

http://perlmaven.com/simple-database-access-using-perl-dbi-and-sql

用于大型数据集的 SQLite?

#!/usr/bin/perl
use strict;
use warnings;

use DBI;

my $dbfile = "sample.db";

my $dsn = "dbi:SQLite:dbname=$dbfile";
my $user = "";
my $password = "";
my $dbh = DBI->connect($dsn, $user, $password, {
PrintError => 1,
RaiseError => 1,
FetchHashKeyName => 'NAME_lc',
AutoCommit => 0,
});
$dbh->do('PRAGMA synchronous = OFF');

my $sql = <<'END_SQL';
CREATE TABLE t1 (
id INTEGER PRIMARY KEY,
c1 VARCHAR(100),
c2 VARCHAR(100),
c3 VARCHAR(100),
c4 VARCHAR(100),
)
END_SQL

$dbh->do($sql);

my $sql = <<'END_SQL';
CREATE TABLE t2 (
id INTEGER PRIMARY KEY,
c1 VARCHAR(100),
c2 VARCHAR(100),
c3 VARCHAR(100),
c4 VARCHAR(100),
)
END_SQL

$dbh->do($sql);

my $sql = <<'END_SQL';
CREATE TABLE t3 (
id INTEGER PRIMARY KEY,
c1 VARCHAR(100),
c2 VARCHAR(100),
c3 VARCHAR(100),
c4 VARCHAR(100),
)
END_SQL

$dbh->do($sql);
### populate data
open my $fh, $ARGV[0] or die "Can't open $ARGV[0] for reading: $!";
while( my $line = <$fh> ){
    my @cols = split('\|', $line);
    $dbh->do('INSERT INTO t1 (id, c1, c2, c3, c4) VALUES (?, ?, ?)',undef,$col[0],$col[1],$col[2],$col[3]);
}
close($fh);
$dbh->commit();
open my $fh, $ARGV[1] or die "Can't open $ARGV[1] for reading: $!";
while( my $line = <$fh> ){
    my @cols = split('\|', $line);
    $dbh->do('INSERT INTO t2 (id, c1, c2, c3, c4) VALUES (?, ?, ?)',undef,$col[0],$col[1],$col[2],$col[3]);
}
close($fh);
$dbh->commit();
open my $fh, $ARGV[2] or die "Can't open $ARGV[2] for reading: $!";
while( my $line = <$fh> ){
    my @cols = split('\|', $line);
    $dbh->do('INSERT INTO t3 (id, c1, c2, c3, c4) VALUES (?, ?, ?)',undef,$col[0],$col[1],$col[2],$col[3]);
}
close($fh);
$dbh->commit();
### process data
my $sql = 'SELECT t1.c1, t1.c2, t1.c3, t2.c2, t2.c3, t3.c2 FROM t1,t2,t3 WHERE t1.c1=t2.c1 AND t1.c1=t3.c1 ORDER BY t1.c1';
my $sth = $dbh->prepare($sql);
$sth->execute(1, 10);
while (my @row = $sth->fetchrow_array) {
    print join("\t",@row)."\n";
}

$dbh->disconnect;
#unlink($dbfile);
于 2013-11-05T16:08:24.003 回答