次のファイルがあります。
ファイル1:
1 2 0.000
1 3 0.213
1 4 0.014
1 5 0.001
1 6 0.555
1 7 0.509
1 8 0.509
3 4 0.995
3 5 0.323
3 6 0.555
3 7 0.225
3 8 0.000
4 5 0.095
4 6 0.058
4 7 0.335
4 8 0.000
5 6 0.995
5 7 0.658
5 8 0.000
6 7 0.431
6 8 0.000
7 8 0.000
ファイル2:
1
3
4
5 6 7
ファイル2で数字のペアが連続して観察されるファイル1の行を維持したいと思います。ここでは、ファイル2から5、6、7のみが観察されます。したがって、各数値ペアはファイル1に残る必要があります。したがって、出力は次のようになります。
5 6 0.995
5 7 0.658
6 7 0.431
どのような提案があります(実際のデータが大きく、数字が1から始まらない可能性があることを考慮)。
答え1
perl
解決策が大丈夫なら。 file1の列1と列2のデータは、列1の値が常に列2よりも小さくなるようにソートされていると仮定します。
$ perl -lane '
if(!$nf)
{
if($#F > 0)
{
foreach $i (0..$#F)
{
$h{"-$F[$i]-$F[$_]-"}++ foreach ($i+1..$#F)
}
}
$nf++ if eof;
}
else
{
print if $h{"-$F[0]-$F[1]-"}
}
' file2 file1
5 6 0.995
5 7 0.658
6 7 0.431
- まず、file2にペアでキーのハッシュを構築します(再度数字が昇順であると仮定)。
- と台などの
-
不整合を防ぐために、2つの列の値を囲みます。11
20
1
120
- と台などの
- 次に、file1 行のキーがある場合は、その行を印刷します。
file2
に変更された場合
$ cat file2
1
3 4
5 6 7 8
$ perl -lane '
if(!$nf)
{
if($#F > 0)
{
foreach $i (0..$#F)
{
$h{"-$F[$i]-$F[$_]-"}++ foreach ($i+1..$#F)
}
}
$nf++ if eof;
}
else
{
print if $h{"-$F[0]-$F[1]-"}
}
' file2 file1
3 4 0.995
5 6 0.995
5 7 0.658
5 8 0.000
6 7 0.431
6 8 0.000
7 8 0.000
答え2
awkを使用してください。
最初の awk コマンドは、すべてのペアを含むファイルを生成します。 2番目のawkコマンドは、ペアファイルを配列に一度読み込み、一致するすべての行を印刷します。
awk 'NF>1{for(i=1;i<=NF;i++) for(j=i+1;j<=NF;j++) print $i,$j;}' file2 > /tmp/pairs
awk 'BEGIN{while((getline <"/tmp/pairs") > 0) pair[$1,$2]=1; close("/tmp/pairs")} ($1,$2) in pair' file1
2番目のコマンドには多くのメモリが必要な場合があります!ファイルが順番に並べられている場合は、何らかの方法で配列を避け、両方のファイルを同時に読み取ることができます。最終実行前にペアファイルを表示するには、2つのコマンドを使用します。
ここのコードは単一のコマンドと同じで読みやすい形式です。
awk '
BEGIN {
f="file2"
while((getline <f) > 0)
for(i=1;i<=NF;i++)
for(j=i+1;j<=NF;j++)
pair[$i,$j]=1;
close(f);
}
($1,$2) in pair
' file1
参考までにfile1(22 mill.lines)、file2(4 mill.lines)に対していくつかのベンチマークを実行して2 mill.linesを作成しました。ライン出力。
- gawk:9.6秒、275Mメモリ
- mawk:20.7秒、134Mメモリ
- SundeepのPerl回答:31.9秒、231Mメモリ