2

Предположим, у меня есть два файла, Файл A:

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

И файл Б:

a
b

Вывод, который я ищу:

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

Итак, в основном я хочу выбрать строки из файла A, где первый столбец соответствует любому значению в файле B, используя стандартные команды unix. Вид awk {if (file_b contains $1} print $1,$2 , но более эффективный.

Ожидаемое количество строк в файле A превышает 20 миллионов, а в файле B 1 миллион. Он должен работать в O(n), поэтому шаг содержит, вероятно, полагаться на хэш-таблицу.

3 ответа3

3

Есть много способов сделать это. Вот некоторые из них, но используйте 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 может пройти файл с 20 миллионами строк и найти 1,5 миллиона шаблонов и завершиться за ~ 40 секунд. Неплохо. Другие два намного медленнее, gawk занял 2,5 минуты, а grep работал более 15. Perl выигрывает руки

2

Это должно сделать трюк:

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

я до сих пор не понимаю, что вы пытаетесь сделать .... у вас уже есть что-то в awk stmt.

grep является базовым и основан на эффективном и быстром алгоритме preety, основанном на индексе возможных совпадений .... 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

это помогает?

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .