AWK частичный поиск строки между двумя файлами - PullRequest
0 голосов
/ 18 марта 2020

Файл 2:

U1664246201||2020-03-01 00:00:00|2020-12-31 00:00:00|abc
U1664246201||2020-03-01 00:00:00|2020-12-31 00:00:00|abc
|R1664236401|2018-03-01 00:00:00|2020-12-31 00:00:00|abc    
U1664546501|R1664546401|2019-04-01 00:00:00|2020-12-30 00:00:00|abc
U1774546301||2020-05-01 00:00:00|2020-12-31 00:00:00|abc

Файл 1:

U17745463
R16645464
R16642364

Текущее решение

awk 'BEGIN {print "columns"} {FS=OFS="|"} NR==FNR{a[$1]; next} {for (i in a) if($1 != "" && $2 != ""){if(index($1, i)){print $0} else {if(index($2, i)){print $0}} } else{ if((index($1, i)) || (index($2, i))){print $0}}}' file2.txt file1.txt > result.txt

Выход:

|R1664236401|2018-03-01 00:00:00|2020-12-31 00:00:00|abc    
U1664546501|R1664546401|2019-04-01 00:00:00|2020-12-30 00:00:00|abc    
U1774546301||2020-05-01 00:00:00|2020-12-31 00:00:00|abc

This Решение дает вывод, но при обработке миллионов записей это занимает больше времени и иногда зависает. Есть ли лучшее решение для этой проблемы?

Ответы [ 2 ]

1 голос
/ 18 марта 2020

Похоже, именно для этого было сделано grep, поэтому я думаю, что оно должно быть более эффективным.

$ grep -f file1 file2
|R1664236401|2018-03-01 00:00:00|2020-12-31 00:00:00|abc
U1664546501|R1664546401|2019-04-01 00:00:00|2020-12-30 00:00:00|abc
U1774546301||2020-05-01  00:00:00|2020-12-31 00:00:00|abc

$ cat file1
U17745463
R16645464
R16642364

$ cat file2
U1664246201||2020-03-01 00:00:00|2020-12-31 00:00:00|abc
U1664246201||2020-03-01 00:00:00|2020-12-31 00:00:00|abc
|R1664236401|2018-03-01 00:00:00|2020-12-31 00:00:00|abc
U1664546501|R1664546401|2019-04-01 00:00:00|2020-12-30 00:00:00|abc
U1774546301||2020-05-01  00:00:00|2020-12-31 00:00:00|abc

Обратите внимание, что опция -f указывает файл, из которого взяты шаблоны .

0 голосов
/ 18 марта 2020

Если perl - ваш вариант, попробуйте следующее:

sort file1 > file1_sorted
sort -t "|" -k 1,1 file2 > file2_sorted_0       # sort by the 1st column
sort -t "|" -k 2,2 file2 > file2_sorted_1       # sort by the 2nd column

perl -e '

for $i (0 .. 1) {                               # repeat twice by changing the order of file2
    open(FH1, "file1_sorted") or die;           # set filehandle for file1_sorted
    open(FH2, "file2_sorted_$i") or die;        # set filehandle for file2_sorted_n

    while (!eof(FH1) || !eof(FH2)) {
        unless (defined $l1) {                  # if marked to update
            $l1 = <FH1>;                        # read next item from FH1
            chomp($l1);                         # remove the newline
        }
        unless (defined $l2) {                  # if marked to update
            $l2 = <FH2>;                        # read next item from FH2
            @ary = split(/\|/, $l2);            # split on "|"
        }
        if ($ary[$i] =~ /^$l1/) {               # test the match
            print $l2;                          # print the matched line
            undef $l1;                          # set mark to update FH1
        } else {
            if ($ary[$i] lt $l1) {              # if FH2 is less than FH1
                undef $l2;                      # set mark to update FH2
            } else {
                undef $l1;                      # else update FH1
            }
        }
    }
}
'
  • Если мы сравниваем два файла построчно, это требует вычисления O(N ** 2) и займет долгое время.
  • Чтобы уменьшить сравнение, мы сортируем файлы заранее и сравниваем записи в stream таким же образом, как мы делаем в pipeline merge sort.
  • Поскольку у нас есть два столбца для сравнения в file2, мы подготовим два файла для file2, изменив ключи сортировки.
  • Тот же лог c может быть реализован также с помощью awk, но позвольте мне используйте perl для этого времени.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...