用perl比较具有相反顺序的行

时间:2013-03-06 11:10:31

标签: perl

我在使用Perl时非常新,我需要用它来比较文件的所有行。该文件有两个以|分隔的ID和每个ID对的值。它看起来像这样:

a|b 9
a|a 1
a|c 4
s|c 3
f|e NA
a|d 2
d|a 2
d|b 5
c|l NA
c|s 3

如果有另一个具有相同ID(字母)的行,我想消除一行,但是按顺序排列(如| d和d | a),我将“NA”作为值的行和两个位置具有相同ID的行(如a | a 1)。 从这里的例子中,我想获得这样的输出:

a|b 9
a|c 4
s|c 3
a|d 2
d|b 5

我正在尝试编写的代码。它可以消除带有“NA”的行和ID相同的行(如| a 1),但是它无法检测具有反转ID的行。

$file = "test.txt";
open (HAN, "$file") || die "No input file";
@r = <HAN>;
close (HAN);
for ($i=0; $i<=$#r; $i++) {
    chomp($r[$i]);      
    ($id, $v) = split (/\t/, $r[$i]);
    if ( $v ne NA ) {
       ($id1, $id2) = split (/\|/, $id);            
        $ii = $id1."|".$id2;
        $dd = $id2."|".$id1;
        if(($id1 ne $id2)||($ii ne $dd)){
           print "$id\t$v\n";
        }
    }       
}

绝对欢迎任何帮助!

提前谢谢你, 加布

3 个答案:

答案 0 :(得分:1)

要解决此问题,您需要跟踪到目前为止遇到的所有对(ID)。处理新行时,需要与ID对列表匹配,以查找它是否为反对。

以下修改使其有效:

$file = "test.txt";
open (HAN, "$file") || die "No input file";
@r = <HAN>;
@encountered;
close (HAN);
for ($i=0; $i<=$#r; $i++) {
    chomp($r[$i]);
    $present=0;
    $invertPr=0;
    ($id, $v) = split (/\t/, $r[$i]);
    if ( $v ne NA ) {
       ($id1, $id2) = split (/\|/, $id);
        if($id1 eq $id2) {
            next;
        }
        for($j = 0; $j < $#encountered; $j+=2) {
            if($encountered[$j] eq $id1 && $encountered[$j+1] eq $id2) {
                $present = 1;
            }
            if($encountered[$j+1] eq $id1 && $encountered[$j] eq $id2) {
                $invertPr = 1;
            }
        }
        if($present == 0) {
           push(@encountered, $id1);
           push(@encountered, $id2);
        }
        if($invertPr == 0) {
           print "$id\t$v\n";
        }
    }
}

答案 1 :(得分:0)

以下脚本始终使用“lower”id作为密钥的第一部分。因此,您不必关心倒置ID:

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

sub compare {
    my %result;
    for (@_) {
        my ($id1, $id2, $value) = /(.+)\|(.+) (.+)/;
        next if $id1 eq $id2 or 'NA' eq $value;
        ($id1, $id2) = sort $id1, $id2;
        next if exists $result{"$id1|$id2"};
        $result{"$id1|$id2"} = $value;
    }
    return join "\n", map "$_ $result{$_}", keys %result;
}

print compare(<DATA>);

__DATA__
a|b 9
a|a 1
a|c 4
s|c 3
f|e NA
a|d 2
d|a 2
d|b 5
c|l NA
c|s 3

答案 2 :(得分:0)

另一种方法,如果之前的2个回复让您感到困惑:

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

my %previous;
open (my $IN,'<','file.txt') or die "$!";
while (<$IN>) {
    my ($tmp,$v)=split/ /;
    next if $v=~/NA/; #remove the rows in which I have "NA" as value 
    my ($id1,$id2)=split/\|/,$tmp;
    next if $id1 eq $id2; #remove the rows with the same ID in both positions
    next if exists $previous{"$id2|$id1"}; #remove the row if there is another with the same IDs (letters), but in an inverted order
    $previous{$tmp}=1;
    print;
}
close $IN;