perl匹配两个文件中的多个列名

时间:2016-05-07 12:21:09

标签: perl

我有两个制表符分隔的文本文件,我想要匹配多个列。

这是表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'。当没有匹配时,空(所以没有价值)。

1 个答案:

答案 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是假的,但是被定义,这是不同的)。