Perl을 사용하여 열을 기준으로 세 개의 파일을 비교합니다.

Perl을 사용하여 열을 기준으로 세 개의 파일을 비교합니다.

세 개의 파일이 있고 파일 1의 첫 번째 열을 파일 2의 첫 번째 열과 일치시킨 다음 파일 1의 두 번째 열을 파일 3의 첫 번째 열과 일치시켜야 합니다.

  • 파일 1에는 다음 줄 등이 포함되어 있습니다.

    • fji01dde AIDJFMGKG  
      dlp02sle VMCFIJGM
      cmr03lspCKEIFJ
      
  • 파일 2에는 다음 줄 등이 포함되어 있습니다.

    • fji01dde 25 30  
      dlp02sle 40 50  
      cmr03lsp 60 70  
      
  • 파일 3에는 다음이 포함됩니다.

    • 엣지있는 FMGKG  
      CKEIFJ  
      
  • 내 예상 결과는 다음과 같습니다

    • fji01dde AIDJFMGKG 25 30  
      cmr03lsp CKEIFJ 60 70  
      
    • 등...

  • 세 파일 모두에서 공통 줄만 원하지만 실행하면...

    • #!/usr/bin/env perl
      use strict;
      use warnings;
      my %data;
      
      while (<>) {  
          my ( $key, $value ) = split;  
          push( @{ $data{$key} }, $value );  
      }  
      
      foreach my $key ( sort keys %data ) {  
          if ( @{ $data{$key} } >= @ARGV ) {  
          print join( "\t", $key, @{ $data{$key} } ), "\n";  
          }    
      }
      
    • 내 결과는 ...

    • 엣지있는 FMGKG  
      CKEIFJ  
      fji01dde 25  
      dlp02sle 40  
      cmr03lsp 60
      

어떤 아이디어가 있나요? 미리 감사드립니다!

답변1

while(<>)스크립트의 주요 문제점은 루프가 끝나면 @ARGV가 비어 있다는 것입니다. 루프를 실행하기 전에 매개변수 개수를 가져와야 합니다. Perl 배열은 0부터 시작하므로 개수에서 1을 빼야 한다는 점을 기억하세요.

이는 요청한 출력을 생성하는 수정된 버전입니다.

$ cat compare.pl 
#!/usr/bin/perl
use strict;
use warnings;

my $numargs=@ARGV-1;
my %data=();

while (<>) {  
    my ( $key, $value ) = split;  
    push( @{ $data{$key} }, $value );  

}  

foreach my $key ( sort keys %data ) {  
    if ( @{ $data{$key} } >= $numargs ) {  
    print join( "\t", $key, @{ $data{$key} } ), "\n";  
    }  
}

$ ./compare.pl file1 file2 file3
cmr03lsp    CKEIFJ  60
dlp02sle    VMCFIJGM    40
fji01dde    AIDJFMGKG   25

답변2

교차 게시된 질문이므로 교차 게시된 답변:

좋아, 보세요. 문제는 split기본적으로 공백으로 분할되기 때문입니다. 이 표준에 따르면 두 번째 파일에는 2개가 아닌 3개의 필드가 있습니다.

또한 - 실제로 동일한 것을 상호 참조하지 않으므로 while ( <> ) {루프가 작동하지 않습니다.

  • 파일 1에서 - 확인하고 싶습니다.
  • file2에서는 키를 확인하고 값을 추가합니다.
  • file3에는 값이 없고 키만 있습니다.

따라서 다음을 고려하십시오.

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

#read file1 into a hash - but invert is it's value => key instead:
#          'CKEIFJ' => 'cmr03lsp',
# etc.  
open( my $file1, '<', "file1.txt" ) or die $!;
my %file1_content = map { reverse split } <$file1>;
close($file1);

print Dumper \%file1_content;

#read file 2 - read keys, store the values. 
#split _2_ fields, so we keep both numbers as a substring:
#e.g.:
#          'cmr03lsp' => '60 70
#',

open( my $file2, '<', "file2.txt" ) or die $!;
my %file2_content = map { split( " ", $_, 2 ) } <$file2>;
close($file2);

print Dumper \%file2_content;    

#then iterate file 3, checking if:
#file1 has a matching 'key' (but inverted - as a value) 
#file2 has a cross reference. 
open( my $file3, '<', "file3.txt" ) or die $!;
while ( my $line = <$file3> ) {
    chomp $line;
    if (    $file1_content{$line}
        and $file2_content{ $file1_content{$line} } )
    {
        print
            "$file1_content{$line} $line $file2_content{$file1_content{$line}}";
    }
}
close($file3);

그러면 다음과 같이 인쇄됩니다("dumper" 출력 제외).

fji01dde AIDJFMGKG 25 30
cmr03lsp CKEIFJ 60 70

관련 정보