当列位于白名单中时过滤文件

当列位于白名单中时过滤文件

假设我有两个文件,文件 A:

a,abcdef
b,bcdefa
c,cdefab
a,defabc
b,efabcd
c,fabcde

文件 B:

a
b

我正在寻找的输出是:

a,abcdef
b,bcdefa
a,defabc
b,efabcd

因此,基本上,我想使用标准 unix 命令从文件 A 中选择第一列与文件 B 中的任意值匹配的行。一种awk {if (file_b contains $1} print $1,$2,但效率更高。

文件 A 中的预期行数超过 2000 万,文件 B 中的预期行数超过 100 万。必须运行时间为 O(n),因此包含步骤可能应该依赖于哈希表。

答案1

许多实现此目的的方法。这里有几个,但使用 Perl 的方法速度要快几个数量级。为了完整起见,我把其他方法也包括进来了:

  1. Perl 和哈希,速度快得离谱

    perl -e 'open(A,"fileB"); while(<A>){chomp; $k{$_}++} 
     while(<>){@a=split(/,/); print if defined $k{$a[0]}}' fileA
    
  2. gawk 和关联数组,速度慢得多

     gawk '{if(FILENAME==ARGV[1]){array[$1]=1}
      else{if($1 in array){print}}}' fileA fileB
    
  3. grep,慢得离谱。你需要稍微修改一下文件 B,让模式只在第一行匹配

    sed 's/\(.\)/^\1/' fileB > fileC
    grep -f fileC fileA  
    

我创建了几个测试文件,结果发现 Perl 解决方案是很多比以下更快grep

$ head -2 fileA
GO:0032513_GO:0050129
GO:0050129_GO:0051712
$ head -2 fileB
GO:0032513_GO:0050129
GO:0050129_GO:0051712
$ wc -l fileA fileB
  1500000 fileA
 20000000 fileB
$ time perl -e 'open(A,"fileB"); while(<A>){chomp; $k{$_}++} 
 while(<>){@a=split(/,/); print if defined $k{$a[0]}}' fileA > /dev/null 

real    0m41.354s
user    0m37.370s
sys     0m3.960s
$ time gawk '{if(FILENAME==ARGV[1]){array[$1]=1}
   else{if($1 in array){print}}}' fileA fileB

real    2m30.963s
user    1m23.857s
sys     0m9.385s
$ time (join -t, <(sort -n fileA) <(sort -n fileB) >/dev/null)

real    8m29.532s
user    13m52.576s
sys     1m22.029s

因此,Perl 脚本可以遍历 2000 万行文件,查找 150 万个模式,并在约 40 秒内完成。还不错。其他两个脚本要慢得多,gawk需要 2.5 分钟,而其中grep一个脚本已经运行了 15 分钟以上。Perl 毫无疑问胜出。

答案2

这应该可以解决问题:

join -t, <(sort A) <(sort B)

答案3

我还是不明白你想做什么....你已经在 awk stmt 中做了一些事情。

grep 是基本的,基于一种基于可能匹配索引的非常高效和快速的算法.... awk 进行单独的比较和检查,所以这应该很快.... wrt awk,这里

 for pat in `cat zfile2` ; do  grep -i "$pat," zfile1 ; done; 

这很好用......

   $ for pat in `cat zfile2` ; do  grep -i "$pat," zfile1 ; done;
   a,abcdef
   a,defabc
   b,bcdefa
   b,efabcd

这有帮助吗?

相关内容