Есть два файла с именами «a.txt» и «b.txt», оба имеют список слов. Теперь я хочу проверить, какие слова являются дополнительными в «a.txt» и не находятся в «b.txt» .
Мне нужен эффективный алгоритм, так как мне нужно сравнить два словаря.
Есть два файла с именами «a.txt» и «b.txt», оба имеют список слов. Теперь я хочу проверить, какие слова являются дополнительными в «a.txt» и не находятся в «b.txt» .
Мне нужен эффективный алгоритм, так как мне нужно сравнить два словаря.
Ответы:
если у вас установлен vim, попробуйте это:
vimdiff file1 file2
или
vim -d file1 file2
Вы найдете это фантастическим.
Сортируйте их и используйте comm
:
comm -23 <(sort a.txt) <(sort b.txt)
comm
сравнивает (сортирует) входные файлы и по умолчанию выводит три столбца: строки, уникальные для a, строки, уникальные для b, и строки, присутствующие в обоих. Указав -1
, -2
и / или -3
вы можете подавить соответствующий вывод. Поэтому comm -23 a b
перечислены только записи, которые являются уникальными для. Я использую <(...)
синтаксис для сортировки файлов на лету, если они уже отсортированы, вам это не нужно.
comm
более эффективен, потому что он выполняет работу за один запуск, не сохраняя весь файл в памяти. Поскольку вы используете словари, которые, скорее всего, уже отсортированы, они вам даже не нужны sort
. Использование grep -f file1 file2
с другой стороны загрузит все file1
в память и сравнит каждую строку file2
со всеми этими записями, что гораздо менее эффективно. Это в основном полезно для маленьких, несортированных -f file1
.
\n
он также будет включен для сравнения.
Вы можете использовать diff
инструмент в Linux, чтобы сравнить два файла. Вы можете использовать параметры --changed-group-format и --unchanged-group-format для фильтрации необходимых данных.
Следующие три параметра можно использовать для выбора соответствующей группы для каждого параметра:
'% <' получить строки из FILE1
'%>' получить строки из FILE2
'' (пустая строка) для удаления строк из обоих файлов.
Например: diff --changed-group-format = "% <" --unchanged-group-format = "" file1.txt file2.txt
[root@vmoracle11 tmp]# cat file1.txt
test one
test two
test three
test four
test eight
[root@vmoracle11 tmp]# cat file2.txt
test one
test three
test nine
[root@vmoracle11 tmp]# diff --changed-group-format='%<' --unchanged-group-format='' file1.txt file2.txt
test two
test four
test eight
Если вы предпочитаете стиль вывода diff из git diff
, вы можете использовать его с --no-index
флагом, чтобы сравнивать файлы не в git-репозитории:
git diff --no-index a.txt b.txt
Используя пару файлов с примерно 200-тысячными строками имен в каждой, я сравнил (с помощью встроенной time
команды) этот подход по сравнению с некоторыми другими ответами здесь:
git diff --no-index a.txt b.txt
# ~1.2s
comm -23 <(sort a.txt) <(sort b.txt)
# ~0.2s
diff a.txt b.txt
# ~2.6s
sdiff a.txt b.txt
# ~2.7s
vimdiff a.txt b.txt
# ~3.2s
comm
кажется самым быстрым на сегодняшний день, в то время как git diff --no-index
кажется самым быстрым подходом для вывода в стиле diff.
Обновление 2018-03-25 Вы можете на самом деле опустить --no-index
флаг, если вы не находитесь в репозитории git и не хотите сравнивать неотслеживаемые файлы в этом репозитории. Из справочных страниц :
Эта форма предназначена для сравнения указанных двух путей в файловой системе. Вы можете опустить опцию --no-index, когда запускаете команду в рабочем дереве, управляемом Git, и хотя бы один из путей указывает за пределы рабочего дерева, или когда запускаете команду вне рабочего дерева, управляемого Git.
Вы также можете использовать: colordiff : отображает вывод diff с цветами.
О vimdiff : позволяет сравнивать файлы через SSH, например:
vimdiff /var/log/secure scp://192.168.1.25/var/log/secure
Извлечено из: http://www.sysadmit.com/2016/05/linux-diferencias-entre-dos-archivos.html
Также не стоит забывать и про mcdiff - внутреннюю программу просмотра различий в GNU Midnight Commander .
Например:
mcdiff file1 file2
Наслаждайтесь!
Использование comm -13
(требуется отсортированные файлы) :
$ cat file1
one
two
three
$ cat file2
one
two
three
four
$ comm -13 <(sort file1) <(sort file2)
four
Вот мое решение для этого:
mkdir temp
mkdir results
cp /usr/share/dict/american-english ~/temp/american-english-dictionary
cp /usr/share/dict/british-english ~/temp/british-english-dictionary
cat ~/temp/american-english-dictionary | wc -l > ~/results/count-american-english-dictionary
cat ~/temp/british-english-dictionary | wc -l > ~/results/count-british-english-dictionary
grep -Fxf ~/temp/american-english-dictionary ~/temp/british-english-dictionary > ~/results/common-english
grep -Fxvf ~/results/common-english ~/temp/american-english-dictionary > ~/results/unique-american-english
grep -Fxvf ~/results/common-english ~/temp/british-english-dictionary > ~/results/unique-british-english
sdiff -s file1 file2
было полезно.
Используя awk для этого. Тестовые файлы:
$ cat a.txt
one
two
three
four
four
$ cat b.txt
three
two
one
Awk:
$ awk '
NR==FNR { # process b.txt or the first file
seen[$0] # hash words to hash seen
next # next word in b.txt
} # process a.txt or all files after the first
!($0 in seen)' b.txt a.txt # if word is not hashed to seen, output it
Дубликаты выдаются:
four
four
Чтобы избежать дубликатов, добавьте каждое вновь встреченное слово в a.txt в seen
хеш:
$ awk '
NR==FNR {
seen[$0]
next
}
!($0 in seen) { # if word is not hashed to seen
seen[$0] # hash unseen a.txt words to seen to avoid duplicates
print # and output it
}' b.txt a.txt
Вывод:
four
Если списки слов разделены запятыми, например:
$ cat a.txt
four,four,three,three,two,one
five,six
$ cat b.txt
one,two,three
Вы должны сделать пару дополнительных кругов ( for
петель):
awk -F, ' # comma-separated input
NR==FNR {
for(i=1;i<=NF;i++) # loop all comma-separated fields
seen[$i]
next
}
{
for(i=1;i<=NF;i++)
if(!($i in seen)) {
seen[$i] # this time we buffer output (below):
buffer=buffer (buffer==""?"":",") $i
}
if(buffer!="") { # output unempty buffers after each record in a.txt
print buffer
buffer=""
}
}' b.txt a.txt
На этот раз выведите:
four
five,six
diff a.txt b.txt
недостаточно?