使用一个键将多个文件连接到一个文件中,并使用perl重新排列列。

使用一个键将多个文件连接到一个文件中,并使用perl重新排列列。,perl,Perl,如果我试图读取多个大文件并使用密钥连接它们,我应该采取什么方法。有可能是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

如果我试图读取多个大文件并使用密钥连接它们,我应该采取什么方法。有可能是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;
使用严格;
使用警告;
打开我的$head、$ARGV[0]或死亡“无法打开$ARGV[0]阅读:$!”;
打开我的$addr、$ARGV[1]或死亡“无法打开$ARGV[1]阅读:$!”;
打开我的$phone,$ARGV[2]或死亡“无法打开$ARGV[2]阅读:$!”;
#打开我的$final、$ARGV[3]或死亡“无法打开$ARGV[3]阅读:$!”;
而(my$line1=和my$line2=和my$line3=)
{
#将文件拆分为字段
my@headValues=split(“\\”,$line1);
my@addrValues=split(“\\\”,$line2);
my@phoneValues=split(“\\”,$line3);
#如果密钥匹配,则加入它们
如果($headValues[0]==$addrValues[0]和$headValues[0]==$phoneValues[0])
{
打印“$headValues[0]|$headValues[1]|$headValues[2]|$addrValues[1]|$addrValues[2]|$phoneValues[1]”;
}
}
接近$head;

试图理解您的文件。您有一个包含头值的文件(不管是什么),一个包含电话号码的文件,还有一个包含地址的文件。对吗?每个文件可以有多个头、地址或电话号码,并且每个文件以某种方式彼此对应

你能举例说明文件中的数据,以及它们之间的关系吗?一旦我对你的数据有了更好的了解,我会尽快更新我的答案

与此同时,是时候了解一下了。引用允许您创建更复杂的数据结构。而且,一旦您理解了引用,就可以转向面向对象的Perl,它将真正允许您处理您不知道可能实现的编程任务

Perl引用允许您拥有哈希的哈希、数组的数组、哈希的数组或数组的哈希,当然,该数组或哈希中的那些数组或哈希本身也可以拥有数组或哈希。也许举个例子会有所帮助

假设您有一组按员工编号分配的人员。我假设您的第一个文件是
员工id |姓名
,第二个文件是
地址|城市|州
,第三个文件是
家庭电话|工作电话

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

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;
现在,您有一个名为
%employees
的散列,由
$employeed\u id
键入,散列中的每个条目都是对另一个散列的引用。你有一堆散列

最终结果是一个由
$employee\u id
键入的单一数据结构(您的
%employees
),但每个字段都可以单独访问。员工编号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上有很多帖子,在我看来是这样的:

我的数据如下所示:

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


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

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

#/usr/bin/perl
严格使用;
使用警告;
使用DBI;
my$dbfile=“sample.db”;
my$dsn=“dbi:SQLite:dbname=$dbfile”;
我的$user=”“;
我的$password=“”;
my$dbh=DBI->connect($dsn、$user、$password、{
PrintError=>1,
RaiseError=>1,
FetchHashKeyName=>NAME\u lc',
自动提交=>0,
});
$dbh->do('PRAGMA synchronous=OFF');
my$sql=do('插入t2(id,c1,c2,c3,c4)值(?,,?)',未定义,$col[0],$col[1],$col[2],$col[3]);
}
收盘价($fh);
$dbh->commit();
打开我的$fh、$ARGV[2]或死亡“无法打开$ARGV[2]阅读:$!”;
while(我的$line=){
my@cols=split(“\\”,$line);
$dbh->do('插入t3(id,c1,c2,c3,c4)值(?,,?)',未定义,$col[0],$col[1],$col[2],$col[3]);
}
收盘价($fh);
$dbh->commit();
###过程数据
my$sql='从t1、t2、t3中选择t1.c1、t1.c2、t1.c3、t2.c2、t2.c3、t3.c2,其中t1.c1=t2.c1和t1.c1=t3.c1按t1.c1排序';
我的$sth=$dbh->prepare($sql);
$sth->execute(1,10);
while(my@row=$sth->fetchrow\u数组){
打印联接(“\t”和@row)。“\n”;
}
$dbh->断开连接;
#取消链接($dbfile);

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

x、 tsv

y、 tsv

命令
join x.tsv y.tsv
生成:

002 X2 Y2
004 X4 Y4

也就是说,它合并具有相同ID的行并丢弃其他行(以保持简单)。

多大是大?每个文件中有多少字节,多少行?哪些文件(如果有)可以有多行具有相同键值?友好提示:
use autodie,然后您就不必执行
打开或关闭
之类的操作。多达16gb的行数和文件数以百万计。head.txt是唯一的。除了head.txt之外,其他所有文件都可以有多行具有相同的键。关于文件内容的更多信息可能会有用(1)文件是否在第1列排序或聚集?(2) 行的顺序重要吗?或者某些行可以重新排序?(3) 与其他文件相比,头文件有多大?(4) 这段代码多久运行一次?一次,还是每天/每周?(5) 是否存在特定的硬件限制,例如内存不足、硬盘驱动器?(6) 如果您可以将您的意图表示为SQL查询,这可能会有所帮助
ajdjadd|oieuqweoqwe|qwoeqwe|(asdad|asdads)|adsadsnrrd|hqweqwe
@#*()#&&###|@#*@#&)(*&!@!|@#@#&(*&@#
#!/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);
001 X1
002 X2
004 X4
002 Y2
003 Y3
004 Y4
002 X2 Y2
004 X4 Y4