Istnieją dwa pliki o nazwach „a.txt” i „b.txt”, oba zawierają listę słów. Teraz chcę sprawdzić, które słowa są dodatkowe w „a.txt”, a których nie ma w „b.txt” .
Potrzebuję wydajnego algorytmu, ponieważ muszę porównać dwa słowniki.
Istnieją dwa pliki o nazwach „a.txt” i „b.txt”, oba zawierają listę słów. Teraz chcę sprawdzić, które słowa są dodatkowe w „a.txt”, a których nie ma w „b.txt” .
Potrzebuję wydajnego algorytmu, ponieważ muszę porównać dwa słowniki.
Odpowiedzi:
jeśli masz zainstalowany vim, spróbuj tego:
vimdiff file1 file2
lub
vim -d file1 file2
uznasz to za fantastyczne.
Sortuj je i używaj comm
:
comm -23 <(sort a.txt) <(sort b.txt)
comm
porównuje (posortowane) pliki wejściowe i domyślnie wyświetla trzy kolumny: wiersze, które są unikalne dla a, wiersze unikalne dla b i wiersze, które są obecne w obu. Określając -1
, -2
i / lub -3
można stłumić odpowiednie wyjście. Dlatego comm -23 a b
wyświetla tylko wpisy, które są unikalne dla. Używam <(...)
składni do sortowania plików w locie, jeśli są już posortowane, nie potrzebujesz tego.
comm
jest bardziej wydajny, ponieważ wykonuje zadanie w jednym przebiegu, bez przechowywania całego pliku w pamięci. Ponieważ używasz słowników, które najprawdopodobniej są już posortowane, nawet sort
ich nie potrzebujesz . Użycie grep -f file1 file2
z drugiej strony załaduje całość file1
do pamięci i porówna każdą linię file2
ze wszystkimi tymi wpisami, co jest znacznie mniej wydajne. Jest to przydatne głównie w przypadku małych, nieposortowanych -f file1
.
\n
będzie on również uwzględniony podczas porównywania.
Możesz użyć diff
narzędzia w systemie Linux, aby porównać dwa pliki. Możesz użyć opcji --changed-group-format i --unchanged-group-format do filtrowania wymaganych danych.
Aby wybrać odpowiednią grupę dla każdej opcji, można skorzystać z trzech opcji:
'% <' pobiera wiersze z PLIKU1
'%>' pobiera linie z PLIKU2
'' (pusty ciąg) do usuwania linii z obu plików.
Np .: 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
Jeśli wolisz styl wyjściowy diff z git diff
, możesz użyć go z --no-index
flagą, aby porównać pliki spoza repozytorium git:
git diff --no-index a.txt b.txt
Używając kilku plików z około 200k ciągami nazw plików w każdym, porównałem (za pomocą wbudowanego time
polecenia) to podejście w porównaniu z niektórymi innymi odpowiedziami tutaj:
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
wydaje się być najszybszym jak dotąd, podczas gdy git diff --no-index
wydaje się być najszybszym podejściem do wyjścia w stylu diff.
Aktualizacja 2018-03-25 W rzeczywistości możesz pominąć --no-index
flagę, chyba że jesteś w repozytorium git i chcesz porównać nieśledzone pliki w tym repozytorium. Ze stron podręcznika :
Ta forma służy do porównania podanych dwóch ścieżek w systemie plików. Możesz pominąć opcję --no-index podczas uruchamiania polecenia w drzewie roboczym kontrolowanym przez Git i co najmniej jedna ze ścieżek wskazuje poza drzewem roboczym lub podczas uruchamiania polecenia poza drzewem roboczym kontrolowanym przez Git.
Możesz także użyć: colordiff : Wyświetla wynik diff z kolorami.
O vimdiff : Umożliwia porównywanie plików przez SSH, na przykład:
vimdiff /var/log/secure scp://192.168.1.25/var/log/secure
Pobrano z: http://www.sysadmit.com/2016/05/linux-diferencias-entre-dos-archivos.html
Nie zapomnij także o mcdiff - wewnętrznej przeglądarce różnic w GNU Midnight Commander .
Na przykład:
mcdiff file1 file2
Cieszyć się!
Użyj comm -13
(wymaga posortowanych plików) :
$ cat file1
one
two
three
$ cat file2
one
two
three
four
$ comm -13 <(sort file1) <(sort file2)
four
Oto moje rozwiązanie:
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
była przydatna.
Używanie do tego awk. Pliki testowe:
$ 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
Wyprowadzane są duplikaty:
four
four
Aby uniknąć duplikatów, dodaj każde nowo poznane słowo w pliku.txt do seen
krzyżyka:
$ 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
Wynik:
four
Jeśli listy słów są oddzielone przecinkami, na przykład:
$ cat a.txt
four,four,three,three,two,one
five,six
$ cat b.txt
one,two,three
musisz zrobić kilka dodatkowych okrążeń ( for
pętli):
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
Wyjście tym razem:
four
five,six
diff a.txt b.txt
nie wystarcza?