このサイトの最初の質問なので、よく説明できない場合でもご了承ください。私も初心者です。 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に印刷します。
- FileBの最初の行のFileBフィールドの名前を配列に保存します
- 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
ロードして自動的に終了する機能があります。open
close