使用密钥将多个文件合并为一个文件,并使用perl重新排列列。

时间:2013-11-05 15:13:50

标签: 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, $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;

3 个答案:

答案 0 :(得分: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的行并丢弃其他行(为了简单起见)。

答案 1 :(得分:0)

尝试了解您的文件。您有一个 head 值的文件(无论是哪个),一个文件填充了电话号码,一个文件填充了地址。那是对的吗?每个文件可以有多个 head 地址电话号码,每个文件都以某种方式相互对应。

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

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

Perl引用允许您拥有散列哈希数组数组哈希数组哈希数组< / em>,当然那个数组或散列中的数组或散列本身可以有数组或散列。也许一个例子会有所帮助。

假设您有一个按员工编号分配的人员哈希值。我假设您的第一个文件是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键入,哈希中的每个条目都是对另一个哈希的引用。你有一个散列哈希

最终结果是由%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
  

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

@#*()#&&###|@#*@#&)(*&!@!|@#@#&(*&@#

答案 2 :(得分:0)

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

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

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

SQLite for large data sets?

#!/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);