У меня есть два файла:
abc.txt
abcd
xyz
pqrs
abc.txt
zzon
mkno
abcd
Я хочу чтобы проверить, есть ли «abcd» в файле mno.txt. Не обязательно, что если «abcd» является первым в abc.txt, он также будет первым в mno.txt. В обоих файлах есть тысячи таких идентификаторов. Я хочу также проверить, сколько идентификаторов нет в mno.txt, которые находятся в abc.txt. Как я могу это сделать?
Если какой-либо из списков слов несортирован, было бы быстрее использовать эффективную структуру данных для запоминания общих слов.
#!/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
Если вы хотите сохранить небольшую память для промежуточного хранения и времени выполнения, вы можете использовать эту несколько более сложную для понимания программу:
#!/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-цифр каждый (см. ответ Оли для настройки):
$ 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 секунды
Если ваша цель - найти общие или необычные строки, comm будет моей командой go-to здесь.
Он сравнивает два файла и показывает - в трех столбцах - строки, которые уникальны для файла 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, вы будете смотреть на гораздо более медленные обороты, и разница будет увеличиваться до такой степени, что это имеет значение.
Мы могли бы использовать 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
, чтобы получить список:
grep -Fwf abc.txt mno.txt
он дает вам нечто похожее на:
abcd
abcd
zef
, если вы хотите просто получить уникальный список, используйте его как: [ ! d2] grep -Fwf abc.txt mno.txt | sort | uniq
и для получения отсчетов:
grep -Fcwv -f abc.txt mno.txt
-F означает: интерпретировать PATTERN как список фиксированных строк вместо регулярных выражений. -f получить шаблоны из ФАЙЛА, который будет abc.txt. мы рассмотрим mno.txt для паттернов -c Подсчитайте количество совпадений -w. Ищите только «целые слова»: соответствующая подстрока должна либо находиться в начале строки, либо должна предшествовать несимметричному составляющему символу. Точно так же он должен быть либо в конце строки, либо сопровождаться неглавным составным символом. Символы Word - это буквы, цифры и символ подчеркивания. -v Отменить поиск Если какой-либо из списков слов несортирован, было бы быстрее использовать эффективную структуру данных для запоминания общих слов.
#!/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
Если вы хотите сохранить небольшую память для промежуточного хранения и времени выполнения, вы можете использовать эту несколько более сложную для понимания программу:
#!/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-цифр каждый (см. ответ Оли для настройки):
$ 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 секунды
Если ваша цель - найти общие или необычные строки, comm будет моей командой go-to здесь.
Он сравнивает два файла и показывает - в трех столбцах - строки, которые уникальны для файла 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, вы будете смотреть на гораздо более медленные обороты, и разница будет увеличиваться до такой степени, что это имеет значение.
Мы могли бы использовать 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
, чтобы получить список:
grep -Fwf abc.txt mno.txt
он дает вам нечто похожее на:
abcd
abcd
zef
, если вы хотите просто получить уникальный список, используйте его как: [ ! d2] grep -Fwf abc.txt mno.txt | sort | uniq
и для получения отсчетов:
grep -Fcwv -f abc.txt mno.txt
-F означает: интерпретировать PATTERN как список фиксированных строк вместо регулярных выражений. -f получить шаблоны из ФАЙЛА, который будет abc.txt. мы рассмотрим mno.txt для паттернов -c Подсчитайте количество совпадений -w. Ищите только «целые слова»: соответствующая подстрока должна либо находиться в начале строки, либо должна предшествовать несимметричному составляющему символу. Точно так же он должен быть либо в конце строки, либо сопровождаться неглавным составным символом. Символы Word - это буквы, цифры и символ подчеркивания. -v Отменить поиск