比较3个制表符分隔文件并在Perl中打印匹配项

时间:2015-10-25 23:19:48

标签: perl

我希望将文件1的第1列与文件2的第1列匹配,然后将文件1的第2列与文件3的第1列匹配,然后打印匹配项。文件中的列由制表符分隔。例如:

文件1:

fji01dde AIDJFMGKG
dlp02sle VMCFIJGM
cmr03lsp CKEIFJ

文件2:

fji01dde 25 30
dlp02sle 40 50
cmr03lsp 60 70

文件3:

AIDJFMGKG
CKEIFJ

输出需要:

fji01dde AIDJFMGKG 25 30
cmr03lsp CKEIFJ 60 70

我只想要所有三个文件中常见的行。

以下代码适用于前两个文件,但我需要合并第三个文件。有什么想法吗?

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

my (%file1,%file2);

## Open the 1st file
open(A,"file1");
while(<A>){
    chomp; 
    ## Split the current line on tabs into the @F array.
    my @F=split(/\t/); 
    push @{$file1{$F[0]}},@F[1..$#F];
} 

## Open the 2nd file
open(B,"file2");
while(<B>){
    chomp; 
    ## Split the current line on tabs into the @F array.
    my @F=split(/\t/); 

    if (defined($file1{$F[0]})) {
        foreach my $col (@{$file1{$F[0]}}) {
            print "$F[0]\t$col\t@F[1..$#F]\n";
        }
    }
}

1 个答案:

答案 0 :(得分:2)

该算法似乎是......

for each line in 1
   if 1.1 and 2.1 match  AND
      1.2 appears in 3.1
   then
      combine 1.1, 1.2, 2.2 and 2.3

因为在解析CSV文件时存在大量边缘情况,所以不要手动执行。使用Text::CSV_XS。它还可以处理将CSV文件转换为哈希值,并且效率很高。

我们要做的是解析所有文件。第一个文件保留为列表,但其他两个文件被放入键入我们要搜索的列的哈希值。

注意:名称$data非常糟糕,但我不知道这些文件代表什么类型的数据。

use strict;
use warnings;
use Text::CSV_XS qw(csv);

my @csv_files = @ARGV;

# Parse all the CSV files into arrays of arrays.
my $data1 = csv( in => $csv_files[0], sep_char => "\t" );

# Parse the other CSV files into hashes of rows keyed on the columns we're going to search on.
my $data2 = csv( in             => $csv_files[1],
                 sep_char       => "\t",
                 headers        => ["code", "num1", "num2"],
                 key => "code"
            );
my $data3 = csv( in             => $csv_files[2],
                 sep_char       => "\t",
                 headers        => ["CODE"],
                 key            => "CODE"
            );

for my $row1 (@$data1) {
    my $row2 = $data2->{$row1->[0]};
    my $row3 = $data3->{$row1->[1]};

    if( $row2 && $row3 ) {
        print join "\t", $row1->[0], $row1->[1], $row2->{num1}, $row2->{num2};
        print "\n";
    }
}

这会将所有文件读入内存。如果文件非常大,这可能是个问题。您可以通过一次迭代file1而不是将其全部插入来减少内存使用量。