Temukan ID dalam satu file yang tidak di yang lain


9

Saya punya dua file:

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • Saya ingin memeriksa apakah "abcd" ada di file mno.txt .
  • Tidak perlu bahwa jika "abcd" pertama kali di abc.txt , itu juga akan menjadi yang pertama di mno.txt .
  • Ada ribuan id seperti itu di kedua file.
  • Saya juga ingin memeriksa berapa id yang tidak ada di mno.txt yang ada di abc.txt .

Bagaimana saya bisa melakukan ini?

Jawaban:


19

Jika tujuan Anda adalah menemukan baris yang umum atau tidak umum, commakan menjadi perintah masuk saya di sini.

Ini membandingkan dua file dan menunjukkan —dalam tiga kolom— baris yang unik untuk file 1, baris yang unik untuk file 2 dan baris yang muncul di kedua file, masing-masing. Anda dapat melewatinya untuk menekan semua output ini juga. Misal comm -1 file1 file2akan menekan kolom pertama, hal-hal unik untuk file1. comm -12 file1 file2hanya akan menunjukkan hal-hal di kedua file.

Ada satu peringatan besar: input harus diurutkan. Kita bisa mengatasi ini.

Ini akan menunjukkan kepada Anda segala sesuatu dalam abc yang tidak dalam mno:

comm -23 <(sort abc.txt) <(sort mno.txt)

Dan Anda bisa menyalurkannya ke wc -luntuk mendapatkan hitungan.


Alasan saya mengikutinya commadalah bahwa begitu file diurutkan, perbandingan berdampingan adalah komputasi yang sangat sederhana. Jika Anda berurusan dengan jutaan ini, itu akan membuat perbedaan.

Ini dapat ditunjukkan dengan beberapa file tiruan. Saya memiliki komputer yang cukup cepat sehingga untuk menunjukkan perbedaan antara pendekatan, saya perlu set sampel yang cukup besar. Saya telah menggunakan 10 juta string 10-char per file.

$ 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

Pemilahan adalah yang paling banyak menghabiskan waktu di tambang. Jika kami berpura-pura bahwa abc.txt statis, kami dapat mengurutkannya terlebih dahulu dan itu membuat perbandingan di masa mendatang jauh lebih cepat:

$ sort abc.txt abc-sorted.txt
$ time comm -23 abc-sorted.txt <(sort mno.txt) | wc -l
... 0m7.426s

Anda mungkin melihat ini dan menganggap beberapa detik tidak relevan tetapi saya harus menyoroti bahwa ini berjalan pada mesin high-end. Jika Anda ingin melakukan ini pada (misalnya) Raspberry Pi 3, Anda akan melihat perputaran jauh lebih lambat dan perbedaan akan meningkat ke titik yang sebenarnya penting.


7

untuk mendapatkan daftar:

grep -Fwf abc.txt mno.txt

itu memberi Anda sesuatu yang mirip dengan:

abcd
abcd
zef

jika Anda ingin mendapatkan daftar unik maka gunakan seperti:

grep -Fwf abc.txt mno.txt | sort | uniq

dan untuk mendapatkan penghitungan:

grep -Fcwv -f abc.txt mno.txt

  • -F berarti: menafsirkan POLA sebagai daftar string tetap, bukan ekspresi reguler.
  • -fdapatkan pola dari FILE yang akan terjadi abc.txt.
  • kami mencari mno.txtpola
  • -c Hitung jumlah kecocokan
  • -wHanya mencari "seluruh kata": substring yang cocok harus berada di awal baris, atau didahului oleh karakter konstituen non-kata. Demikian pula, harus di akhir baris atau diikuti oleh karakter konstituen non-kata. Karakter penyusun kata adalah huruf, angka, dan garis bawah.
  • -v Balikkan pencarian

1
Jika OP menginginkan jumlah dari non pertandingan, tidak harus yang lebih seperti grep -cxvFf abc.txt mno.txt?
steeldriver

Hanya melihatnya: D ... Anda selalu di sini untuk menyelamatkan saya: D
Ravexina

FYI the fgrep, egrepalternatif seharusnya sudah usang (mendukung grep -F, grep -E- meskipun saya tidak yakin ada yang percaya mereka akan pernah pergi
steeldriver

Apakah perlu digunakan -xsaat menggunakan -F?
Ravexina

1
Tergantung apa yang ingin dihitung OP secara tepat - mis. Jika mno.txt berisi abcdefharuskah hal itu dianggap sebagai kecocokan atau ketidakcocokan abcd?
steeldriver

3

Kita bisa menggunakan awk untuk melakukan pekerjaan dengan melewatkan dua file, pertama file pola, lalu file yang ingin kita periksa. Ketika kita membaca file pertama, kita tahu itu NR==FNRdan pada saat itu kita dapat membaca baris ke dalam array. Ketika NR!=FNRkami memeriksa apakah array untuk baris tersebut diatur.

$ 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

Sebaliknya, kita dapat meniadakan pola untuk mencetak garis yang tidak ada abc.txt

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt       
zzon
mkno

Dan jika kita ingin mencetak hitungan yang bisa kita pakai sortdan wc:

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt | sort -u | wc -l         
2

Saya pikir Anda salah paham. Sejauh yang saya mengerti pertanyaannya, OP ingin menghitung (ukuran) perbedaan set abc.txt- mno.txtyang {xyz, pqrs}.
David Foerster

2

Jika salah satu dari daftar kata tidak disortir, akan lebih cepat untuk menggunakan struktur data yang efisien untuk mengingat kata-kata umum.

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

Pemakaian:

python3 set-difference.py abc.txt mno.txt

Python (lebih efisien)

Jika Anda ingin menghemat sedikit memori untuk penyimpanan perantara dan menjalankan waktu, Anda dapat menggunakan program yang sedikit lebih sulit dimengerti ini:

#!/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

Performa

Diberikan abc.txtdan mno.txtdengan 1 mio baris tidak disortir masing-masing 10 karakter ASCII acak (lihat jawaban Oli untuk pengaturannya):

$ 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

total: 23 detik

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.