【问题标题】:Using perl hash for comparing columns of 2 files使用 perl 哈希比较 2 个文件的列
【发布时间】:2012-01-31 10:29:00
【问题描述】:

我已经问过这个问题了(不好意思再问,这次不一样也很难)但是我尝试了很多但没有达到结果。

我有 2 个大文件(制表符分隔)。

第一个文件 ->

Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8
101_#2 1 H F0 263 278 2 1.5
102_#1 1 6 F1 766 781 1 1.0
103_#1 2 15 V1 526 581 1 0.0
103_#1 2 9 V2 124 134 1 1.3
104_#1 1 12 V3 137 172 1 1.0
105_#1 1 17 F2 766 771 1 1.0

第二个文件->

Col1 Col2 Col3 Col4
97486 H 262 279
67486 9 118 119
87486 9 183 185
248233 9 124 134

如果 col3 值/字符(文件 1)和 col2 值/字符(文件 2)相同,然后将文件 1 的 col5 和 col6(如范围值)与文件 2 的 col3 和 col4 进行比较,如果文件范围1 存在于文件 2 中,然后返回该行(来自 file1)并在输出中添加来自 file2 的额外列 1。

预期输出 ->

Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9
101_#2 1 H F0 263 278 2 1.5 97486
103_#1 2 9 V2 124 134 1 1.3 248233 

到目前为止,我已经尝试了一些带有哈希的东西->

@ARGV or die "No input file specified";
open my $first, '<',$ARGV[0] or die "Unable to open input file: $!";
open my $second,'<', $ARGV[1] or die "Unable to open input file: $!";
print scalar (<$first>);
while(<$second>){
    chomp;
    @line=split /\s+/;
    $hash{$line[2]}=$line[3];
}
while (<$first>) {
    @cols = split /\s+/;
    $p1 = $cols[4];
    $p2 = $cols[5];
    foreach $key (sort keys %hash){
        if ($p1>= "$key"){
            if ($p2<=$hash{$key})
            {
                print join("\t",@cols),"\n";
            }
        }
        else{ next; }
    }
}

但是在上面的代码中没有比较 col3 值/字符(文件 1)和 col2 值/字符(文件 2)。 但这也需要大量时间和内存。任何人都可以建议我如何使用散列或散列的散列使其快速。非常感谢。

大家好,

非常感谢您的帮助。我为自己的问题找到了一种有效的方法。

@ARGV or die "No input file specified";
open $first, '<',$ARGV[0] or die "Unable to open input file: $!";
open $second,'<', $ARGV[1] or die "Unable to open input file: $!";
print scalar (<$first>);


while(<$second>){
chomp;
@line=split /\s+/;

    $hash{$line[1]}{$line[2]}{$line[3]}= $line[0];
    }
while (<$first>) {

    @cols = split /\s+/;

foreach  $key1 (sort keys %hash) {
   foreach $key2 (sort keys %{$hash{$key1}}) {
        foreach  $key3 (sort keys %{$hash{$key1}{$key2}}) {
        if (($cols[2] eq $key1) && ($cols[4]>=$key2) && ($cols[5]<=$key3)){
            print join("\t",@cols),"\t",$hash{$key1}{$key2}{$key3},"\n";

        }   
        last;
    }

}
}
}

对吗?

【问题讨论】:

    标签: perl


    【解决方案1】:

    您不需要两个哈希表。您只需要一个从第一个文件中的条目构建的哈希表,当您遍历第二个文件时,使用defined 检查第一个文件哈希表中是否有键。

    如果有键,则对其他列的值进行比较(我们将第一个文件中的值存储在哈希表中,用于第三列的键)。

    如果没有密钥,那么要么warndie,要么让脚本继续运行,不说什么,如果这是你想要的:

    #!/usr/bin/perl -w
    
    use strict;
    use warnings;
    
    my $firstHashRef;
    
    open FIRST, "< $firstFile" or die "could not open first file...\n";
    while (<FIRST>) { 
        chomp $_;
        my @elements = split "\t", $_;
        my $col3Val = $elements[2];  # Perl arrays are zero-indexed
        my $col5Val = $elements[4];
        my $col6Val = $elements[5];
    
        # keep the fifth and sixth column values on hand, for
        # when we loop through the second file...
    
        if (! defined $firstHashRef->{$col3Val}) { 
            $firstHashRef->{$col3Val}->{Col5} = $col5Val; 
            $firstHashRef->{$col3Val}->{Col6} = $col6Val; 
        }
    }
    close FIRST;
    
    open SECOND, "< $secondFile" or die "could not open second file...\n";
    while (<SECOND>) {
        chomp $_;
        my @elements = split "\t", $_;
        my $col2ValFromSecondFile = $elements[1];
        my $col3ValFromSecondFile = $elements[2];
        my $col4ValFromSecondFile = $elements[3];
    
        if (defined $firstHashRef->{$col2ValFromSecondFile}) {
            # we found a matching key
            # 1. Compare $firstHashRef->{$col2ValFromSecondFile}->{Col5} with $col3ValFromSecondFile
            # 2. Compare $firstHashRef->{$col2ValFromSecondFile}->{Col6} with $col4ValFromSecondFile
            # 3. Do something interesting, based on comparison results... (this is left to you to fill in)
        }
        else {
            warn "We did not locate entry in hash table for second file's Col2 value...\n";
        }
    }
    close SECOND;
    

    【讨论】:

      【解决方案2】:

      只使用awk 怎么样 -

      awk '
      NR==FNR && NR>1{a[$3]=$0;b[$3]=$5;c[$3]=$6;next} 
      ($2 in a) && ($3<=b[$2] && $4>=c[$2]) {print a[$2],$1}' file1 file2
      

      输入数据:

      [jaypal:~/Temp] cat file1
      Col1           Col2    Col3 Col4     Col5        Col6       Col7    Col8
      101_#2          1       H    F0       263        278        2       1.5
      109_#2          1       H    F0       263        278        2       1.5
      102_#1          1       6    F1       766        781        1       1.0
      103_#1          2       15   V1       526        581        1       0.0
      103_#1          2       9    V2       124        134        1       1.3
      104_#1          1       12   V3       137        172        1       1.0
      105_#1          1       17   F2       766        771        1       1.0
      
      [jaypal:~/Temp] cat file2
      Col1    Col2    Col3    Col4
      97486   H       262     279
      67486   9       118     119
      87486   9       183     185
      248233  9       124     134
      

      测试:

      [jaypal:~/Temp] awk '
      NR==FNR && NR>1{a[$3]=$0;b[$3]=$5;c[$3]=$6;next} 
      ($2 in a) && ($3<=b[$2] && $4>=c[$2]) {print a[$2],$1}' file1 file2
      101_#2          1       H    F0       263        278        2       1.5 97486
      103_#1          2       9    V2       124        134        1       1.3 248233
      

      【讨论】:

      • 感谢您的回复。但是 awk 只给出 1 行的结果,而且我对 awk 也不是很熟悉。
      • 您有与上面提供的不同的数据集吗?上述数据集产生两行数据,如您的预期输出所示。
      • 是的,它是一样的,但有更多的行。并且 file1 中的某些行完全相同(file1 的 col1 中的 ID 不同),那么 awk 命令不会同时给出这两行,而只给出 1 行。
      • 如果你没问题,你能给我一些不匹配的样本数据。可能是 awk 解决方案需要一些小改动。
      • 109_#2 1 H F0 263 278 2 1.5 我已将此行作为第 2 行插入到 file1 中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 2011-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多