説明する

説明する

このサイトの最初の質問なので、よく説明できない場合でもご了承ください。私も初心者です。 PerlとUnixのコマンドラインエントリを調べましたが、この問題を解決する方法がわかりません。

2つのファイルがあります。ファイルAは基本ファイルで、10を超える列と約15,000行を含み、ファイルBには4列と約1500行が含まれています。

ファイルBの各行を一度に1つずつ取得し、その列をファイルAの対応する列と一致させたい(2つのファイルの順序は異なりますが、列ヘッダーは同じです)。ファイルAのファイルBの4つの列がすべて一致する場合は、ファイルAから行全体を削除して新しいファイル(ファイルC)に配置します。


例:

ファイルA

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 4   57497067    na  no  612 612 DonorAR2
54  Baillie2011 X   154790187   TMLHE   no  612 612 DonorAR2
54  Baillie2011 5   159351203   ADRA1B  no  612 612 DonorAR2
54  Baillie2011 13  79259801    na  no  612 612 DonorAR2
54  Baillie2011 8   4452925 CSMD1   no  610 610 DonorAH

文書B

study_id.x  sample_name chromosome  g_start
Baillie2011 DonorAH 8   4452925
Baillie2011 DonorBC 9   5491376
Baillie2011 DonorAH 8   5829283
Baillie2011 DonorCH 8   5829283

結果:

ファイルA

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 4   57497067    na  no  612 612 DonorAR2
54  Baillie2011 X   154790187   TMLHE   no  612 612 DonorAR2
54  Baillie2011 5   159351203   ADRA1B  no  612 612 DonorAR2
54  Baillie2011 13  79259801    na  no  612 612 DonorAR2

ファイルC

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 8   4452925 CSMD1   no  610 610 DonorAH

ベストアンサー1

perl -MFatal='open,close' -ali -ne '
   if ( @ARGV ) { # FileB readin
      if ( $. == 1 ) { push @names, @F;      }
      else           { push @A, join $/, @F; }
      print;
   } else { # FileA readin
      if ( $. == 1 ) {
         open FILEC, ">", "FileC.out";
         print FILEC $_;
         print;
         @remap =
            map {
               my $n = $names[$_];
               grep { $n eq $F[$_] } 0 .. $#F;
            } 0..$#names;
      } else {
         my $n = join $/, @F[@remap];
         if ( grep { $n eq $_ } @A ) { print FILEC $_; }
         else                        { print;          }
      }
   }
   eof and $. = 0;
   eof() and close FILEC;
' FileB FileA

説明する

  • Perlコマンドラインに、「FileB」と「FileA」という2つのファイルを順番に指定します。
  • FileBを読み込む過程で、最初の行か別の行なのかによって2つのことを行います。
    • FileBの最初の行のFileBフィールドの名前を配列に保存します@names
    • 他の行の場合は、デフォルトで提供されている@A改行で連結されたフィールドで配列を埋めます。\n$/RS
    • Perlどちらの場合も、sモード-iでFileBを失うことなく読み取るために、この行をSTDOUTに印刷します。
  • FileAを読み取るときにファイルをFILEC埋めるために、最初の行で書き込みファイルハンドルを開きますFileC.out
    • FileBでこの行を保持したいので、STDOUTとして印刷します。
    • また、ヘッダーがFileC.outにも入るように、ファイルハンドルFILECに印刷します。
    • これは、FileBのフィールドがFileAのフィールドにマップされる重要なステップです。
  • FileAの最初の行以外では、これらの再マップされたフィールドとすでに配列に格納されているFileBデータとの間の同一性チェックを実行します@A
  • 一致するものが見つかると、この行はFileC.outに書き込まれ、FileAには書き込まれません。一致するものがない場合、FileAは記録されますが、FileC.outは記録されません。
  • 両方のファイルの終わりに行カウンターを$.ゼロにリセットして、最初の行同一性チェックを両方のファイルで実行できるようにします。
  • 最後のeof(eof()で検出された)の後にファイルハンドルFILECを閉じます。
  • このモジュールには、これらのタスクをFatal.pmロードして自動的に終了する機能があります。openclose

おすすめ記事