2013-03-06 2 views
0

저는 Perl을 사용하는 데있어서 아주 새로운데, 파일의 모든 행을 비교할 때 사용해야합니다. 파일에는 두 ID가 | 분리되어 있습니다. 및 각 ID 쌍에 대한 값. 그것은 다음과 같습니다perl을 사용하여 행의 역순으로 행을 비교하십시오.

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 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"; 
     } 
    }  
} 

아무 도움이 절대적으로 환영합니다!

는 (ID의)는 지금까지 발생한 모든 쌍을 추적 할 필요가 갑

답변

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; 
+0

감사합니다 ... 매우 간단하고 명확한 설명! – Gabelins

1

이 문제를 해결하기 위해, 사전에 감사합니다. 새로운 행이 처리 될 때, 역 쌍인지를 알아 내기 위해 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"; 
     } 
    } 
} 
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 
+0

죄송합니다 ... 난 당신의 코드를 이해하지 않습니다. .. :( – Gabelins

+0

@ Gabelins : 죄송합니다, 단순화. – choroba

관련 문제