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

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

abc.txt

abcd
xyz
pqrs

mno.txt

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

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

9
задан 26 June 2017 в 05:55

4 ответа

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

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 средства: интерпретируйте ШАБЛОН как список фиксированных строк вместо регулярных выражений.
  • -f получают шаблоны из ФАЙЛА который, собираясь быть abc.txt.
  • мы изучаем mno.txt для шаблонов
  • -c, рассчитывают, количество соответствий
  • -w Только ищут "целые слова": подстрока соответствия должна или быть в начале строки или предшествовала символом составляющей неслова. Точно так же это должно быть или в конце строки или сопровождается символом составляющей неслова. Составляющие Word символы являются буквами, цифрами и подчеркиванием.
  • -v Реверс поиск
7
ответ дан 23 November 2019 в 04:46

Если Ваша цель состоит в том, чтобы найти общие или редкие строки, 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, Вы будете смотреть на намного более медленные благоприятные повороты, и различие увеличится до точки, это на самом деле имеет значение.

19
ответ дан 23 November 2019 в 04:46

Мы могли использовать 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
3
ответ дан 23 November 2019 в 04:46

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

Python

#!/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 mio неотсортированные строки 10 случайных символов цифры ASCII каждый (см. ответ Oli для установки):

$ 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 секунды

2
ответ дан 23 November 2019 в 04:46

Другие вопросы по тегам:

Похожие вопросы: