我有两个制表符分隔的文本文件,我想要匹配多个列。
这是表1的结构。它可以具有可变数量的列。所以我想使用标题与table2进行匹配
a x y b c d z
1 . . 1 1 1 .
2 . . 2 2 2 .
3 . . 6 6 3 .
4 . . 4 4 4 .
这是table2的结构。列数&行数总是一样的。第一行是标题
a b c d e f
1 1 1 1 yes no
2 2 2 2 no no
3 3 3 3 no yes
现在,如果两个表中a,b,c和d列的值之间存在匹配,我想向table2添加两个额外的列,其中包含table2中列'e'和'f'的值。
我通常使用perl来实现这个目的。使用哈希
这就是我所拥有的
my %hash = ();
while(<$table2>){
chomp;
my @cols = split(/\t/);
my $keyfield = $cols[0];
my $keyfield2 = $cols[1];
my $keyfield3 = $cols[2];
my $keyfield4 = $cols[3];
push @{ $hash{$keyfield} }, $keyfield2, $keyfield3, $keyfield4;
}
seek $table1,0,0; #cursor resetting
while(<$table1>){
chomp;
my @cols = split(/\t/);
my $keyfield = $cols[...]; #how can I make a match here based on the column names
if (exists($hash{$keyfield})){
print ... #how can I add two extra columns to the existing $table1?
}
else {
print ...
}
}
所以我有两个问题:
如何根据列名
在此处进行匹配如何在现有的$ table1中添加两个额外的列?
输出应如下所示:
a x y b c d z e f
1 . . 1 1 1 . yes no
2 . . 2 2 2 . no no
3 . . 6 6 3 . 'empty' 'empty'
4 . . 4 4 4 . 'empty' 'empty'
所以$ table1有两个额外的列,当匹配时,值为'e'和'f'。当没有匹配时,空(所以没有价值)。
答案 0 :(得分:2)
这里的诀窍是将您的第一个数据读入哈希值,并使用“查找”键入“数据”。
然后,运行引用表 - 您使用哈希切片,这样您就可以通过命名键查找。如果存在;打印。如果没有,请替换为所需的结果。 例如。像这样的东西:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
open( my $table1, '<', 'data1.txt' ) or die $!;
open( my $table2, '<', 'data2.txt' ) or die $!;
chomp( my @header = split /\t/, <$table2> );
my %lookup;
while (<$table2>) {
print;
chomp;
my @row = split /\t/;
#put values into lookup hash, keying on 4 values, to retrieve 'e' and 'f'
#could do this like the below, if you wanted to use named values.
$lookup{ $row[0] }{ $row[1] }{ $row[2] }{ $row[3] } = [ $row[4], $row[5] ];
}
print Dumper \%lookup;
#read one line - the header row - and split it into an array.
chomp( my @header_for_table1 = split /\t/, <$table1> );
print join "\t", @header_for_table1, "e", "f", "\n";
while (<$table1>) {
chomp;
my %row;
@row{@header_for_table1} = split /\t/;
print join ( "\t", @row{@header_for_table1},
@{ $lookup{ $row{a} }{ $row{b} }{ $row{c} }{ $row{d} }
// [ "empty", "empty" ] }), "\n";
}
注意//
运算符是perl 5.10+。在这种情况下,您可以使用||
,但如果您可能存储零或空字符串,请稍微谨慎一些。 (因为0
是假的,但是被定义,这是不同的)。