0

私はPerlの使用にかなり慣れていないので、ファイルのすべての行を比較するためにPerlを使用する必要があります。ファイルには、|で区切られた2つの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";
        }
    }       
}

どんな助けでも大歓迎です!

よろしくお願いします、Gab

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

前の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;
于 2013-03-07T14:16:34.910 に答える
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 に答える