Знайдіть ідентифікатори в одному файлі, які не є в іншому


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би була моя команда go-to.

Він порівнює два файли та показує - у трьох стовпцях - рядки, унікальні для файлу 1, рядки, унікальні для файлу 2, та рядки, що відображаються в обох файлах відповідно. Ви можете передати його прапорами, щоб придушити будь-який з цих результатів. Наприклад comm -1 file1 file2, придушить перший стовпець, унікальні для файлу речі1. 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отримати шаблони з FILE, які будуть abc.txt.
  • ми розглядаємо mno.txtшаблони
  • -c Порахуйте кількість збігів
  • -wШукайте лише "цілі слова": відповідна підрядка повинна бути або на початку рядка, або перед нею складовим символом без слова. Аналогічно, воно повинно бути або в кінці рядка, або після нього несловним складовим символом. Словоскладовими символами є букви, цифри та підкреслення.
  • -v Зворотний пошук

1
Якщо ОП хоче розраховувати кількість невідповідних матчів, чи не варто це більше нагадувати grep -cxvFf abc.txt mno.txt?
steeldriver

Щойно побачив це: D ... ваш завжди тут, щоб врятувати мене: D
Ravexina

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

Чи потрібно використовувати -xпід час використання -F?
Ravexina

1
Це залежить від того, що ОП хоче точно рахувати - наприклад, якщо mno.txt містить, чи abcdefслід це вважати збігом чи невідповідним abcd?
steeldriver

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

Я думаю, у вас це неправильно. Наскільки я розумію питання, ОП хоче обчислити (розмір) заданої різниці 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

vs.

$ 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.