我希望将文件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";
}
}
}
答案 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而不是将其全部插入来减少内存使用量。