Найти идентификаторы в одном файле, которых нет в другом


9

У меня есть два файла:

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • Я хочу проверить, есть ли "abcd" в файле mno.txt .
  • Нет необходимости, чтобы, если «abcd» был первым в abc.txt , он также будет первым в mno.txt .
  • В обоих файлах тысячи таких идентификаторов.
  • Я хочу также проверить, сколько идентификаторов не в mno.txt, которые находятся в abc.txt .

Как я могу это сделать ?

Ответы:


19

Если ваша цель состоит в том, чтобы найти общие или необычные строки, commмоя команда будет здесь.

Он сравнивает два файла и показывает - в трех столбцах - строки, которые являются уникальными для файла 1, строки, которые являются уникальными для файла 2, и строки, которые появляются в обоих файлах соответственно. Вы можете передать ему флаги, чтобы подавить любой из этих выходных данных. Например, comm -1 file1 file2будет подавлен первый столбец, уникальные для file1. comm -12 file1 file2будет показывать только вещи в обоих файлах.

Есть одна большая оговорка: входные данные должны быть отсортированы. Мы можем обойти это.

Это покажет вам все в abc, чего нет в mno:

comm -23 <(sort abc.txt) <(sort mno.txt)

И вы можете передать это, wc -lчтобы получить счет.


Причина, по которой я согласен, commзаключается в том, что после сортировки файлов параллельное сравнение в вычислительном отношении действительно просто. Если вы имеете дело с миллионами из них, это будет иметь значение.

Это можно продемонстрировать с помощью нескольких фиктивных файлов. У меня довольно быстрый компьютер, поэтому, чтобы показать разницу между подходами, мне нужен довольно большой набор образцов. Я пошел на 10 миллионов 10-символьных строк на файл.

$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > abc.txt
$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > mno.txt

$ time comm -23 <(sort abc.txt) <(sort mno.txt) | wc -l
... 0m10.653s

$ time grep -Fcxv -f abc.txt mno.txt
... 0m23.920s

$ time grep -Fcwv -f abc.txt mno.txt
... 0m40.313s

$ time awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt | wc -l
... 0m12.161s

Сортировка - это то, что занимает большую часть времени у меня. Если мы притворимся, что abc.txt является статическим, мы можем предварительно отсортировать его, что значительно ускоряет будущие сравнения:

$ sort abc.txt abc-sorted.txt
$ time comm -23 abc-sorted.txt <(sort mno.txt) | wc -l
... 0m7.426s

Вы можете посмотреть на это и считать несколько секунд неуместными, но я должен подчеркнуть, что они работают на высокопроизводительном компьютере. Если вы хотите сделать это на (например) Raspberry Pi 3, вы будете смотреть на гораздо более медленные обороты, и разница увеличится до точки, которая на самом деле имеет значение.


7

чтобы получить список:

grep -Fwf abc.txt mno.txt

это дает вам что-то похожее на:

abcd
abcd
zef

если вы хотите просто получить уникальный список, используйте его следующим образом:

grep -Fwf abc.txt mno.txt | sort | uniq

и чтобы получить счет:

grep -Fcwv -f abc.txt mno.txt

  • -F означает: интерпретировать PATTERN как список фиксированных строк вместо регулярных выражений.
  • -fполучить шаблоны из файла, который будет abc.txt.
  • мы смотрим на mno.txtшаблоны
  • -c Подсчитайте количество совпадений
  • -wИщите только «целые слова»: соответствующая подстрока должна быть либо в начале строки, либо предшествовать не состоящему из слов символу. Точно так же он должен быть либо в конце строки, либо следовать за символом, не входящим в состав слова. Составляющие слова символы - это буквы, цифры и подчеркивание.
  • -v Обратный поиск

1
Если OP хочет подсчет из не являющихся матчей, не следует , что больше похоже grep -cxvFf abc.txt mno.txt?
Steeldriver

Просто видел это: D ... Вы всегда здесь, чтобы спасти меня: D
Ravexina

FYI fgrep, egrepчередуется якобы осуждается (в пользу grep -F, grep -E- хотя я не уверен , что кто -то считает , что они когда - нибудь уйти
steeldriver

Нужно ли использовать -xпри использовании -F?
Равексина

1
Это зависит от того, что ОП хочет считать точно - например, если mno.txt содержит, abcdefдолжно ли это считаться совпадением или несоответствием abcd?
стальной водитель

3

Мы могли бы использовать awk для выполнения работы, передав два файла: сначала файл шаблона, а затем файл, который мы хотим проверить. Когда мы читаем первый файл, мы знаем это, NR==FNRи тогда мы можем читать строки в массив. Когда NR!=FNRмы проверяем, установлен ли массив для такой строки.

$ cat abc.txt                                                      
abcd
xyz
pqrs
$ cat mno.txt                                                      
zzon
xyz
mkno
abcd
$ awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt         
xyz
abcd

И наоборот, мы можем отменить шаблон для печати тех строк, которые не находятся в abc.txt

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt       
zzon
mkno

И если мы хотим напечатать количество тех, кого мы можем использовать sortи wc:

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt | sort -u | wc -l         
2

Я думаю, что вы ошиблись. Насколько я понимаю вопрос, OP хочет рассчитать (размер) установленную разницу abc.txt- mno.txtкоторая есть {xyz, pqrs}.
Дэвид Фёрстер

2

Если какое-либо из списков слов не отсортировано, было бы быстрее использовать эффективную структуру данных набора для запоминания общих слов.

питон

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = frozenset(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = frozenset(map(str.rstrip, subtrahend_file))

difference = minuend - subtrahend
#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

Применение:

python3 set-difference.py abc.txt mno.txt

Python (более эффективный)

Если вы хотите сэкономить немного памяти для промежуточного хранилища и времени выполнения, вы можете использовать эту немного более сложную для понимания программу:

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = set(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = map(str.rstrip, subtrahend_file)
    minuend.difference_update(subtrahend)
    difference = minuend
    del minuend

#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

Представление

Дано abc.txtи mno.txtс 1 млн несортированных строк по 10 случайных цифр ASCII в каждой (см. Ответ Оли для настройки):

$ time python3 set-difference.py abc.txt mno.txt
user    0m10.453s

против

$ export LC_COLLATE=C
$ time sort abc.txt > abc_sorted.txt
user    0m10.652s
$ time sort mno.txt > mno_sorted.txt
user    0m10.767s
$ time comm -23 abc_sorted.txt mno_sorted.txt | wc -l
9989882
user    0m1.600s

всего: 23 секунды

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.