0

我对使用 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(字母),但顺序相反(如 a|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|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";
        }
    }       
}

绝对欢迎任何帮助!

提前谢谢你,加布

4

3 回答 3

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";
        }
    }
}
于 2013-03-06T11:26:47.893 回答
0

以下脚本始终使用“较低”的 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
于 2013-03-06T11:35:09.640 回答
0

只是另一种方法,以防前两个回答让您感到困惑:

#!/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;
于 2013-03-07T14:16:34.910 回答