如何根据第二个文件中的信息删除第一个文件中的某些行?

如何根据第二个文件中的信息删除第一个文件中的某些行?

我有一个这样的文件:

文件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 上成对构建密钥的哈希值(再次假设数字按升序排列)
    • 两列值被包围-以防止可能的不匹配,例如11and201and120
  • 然后对于 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内存

相关内容