我有一个这样的文件:
文件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
我想将这些行保留在文件 1 中,其中在文件 2 中连续观察到对数字。这里,在文件 2 中仅观察到 5、6 和 7。因此,每一对数字都应保留在文件 1 中。所以输出是:
5 6 0.995
5 7 0.658
6 7 0.431
有什么建议吗(考虑到实际数据很大并且数字可能不是从1开始)?
答案1
如果perl
解决办法没问题的话。假设 file1 中的 column1 和 column2 数据经过排序,使得 column1 中的值始终小于 column2
$ 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 上成对构建密钥的哈希值(再次假设数字按升序排列)
- 两列值被包围
-
以防止可能的不匹配,例如11
and20
与1
and120
- 两列值被包围
- 然后对于 file1 行,如果 key 存在则打印该行
如果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 命令创建一个包含所有对的文件。第二个 awk 命令将pairs文件读取一次到数组中,然后打印所有匹配的行。
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
第二个命令可能需要大量内存!如果文件是有序的,那么我们可以以某种方式避免数组,同时读取两个文件。请注意,我使用两个命令以便能够在最终运行之前查看对文件。
这里的代码与单个命令相同并且格式可读:
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内存