Bir dosyada diğerinde olmayan kimlikleri bulma


9

İki dosyam var:

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • Mno.txt dosyasında "abcd" olup olmadığını kontrol etmek istiyorum .
  • Abc.txt dosyasında ilk olarak "abcd" ise, mno.txt dosyasında da ilk sırada yer alması gerekmez .
  • Her iki dosyada da binlerce kimlik var.
  • Ben de olmayan kaç id en denetlemek istediğiniz mno.txt içindedir abc.txt .

Bunu nasıl yapabilirim ?

Yanıtlar:


19

Amacınız ortak veya yaygın olmayan satırlar bulmaksa, commburadaki go-to komutum olacaktır.

İki dosyayı karşılaştırır ve (üç sütunda) dosya 1'e özgü satırları, dosya 2'ye özgü satırları ve her iki dosyada da görünen satırları gösterir. Bu çıktılardan herhangi birini bastırmak için bayrakları geçirebilirsiniz. Örneğin comm -1 file1 file2, birinci sütunu, dosya1'e özgü şeyleri bastıracaktır. comm -12 file1 file2yalnızca her iki dosyada da bir şeyler gösterirdi.

Büyük bir uyarı var: giriş sıralanmalıdır. Bu sorunu çözebiliriz.

Bu size mno'da olmayan abc'deki her şeyi gösterecektir:

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

Ve wc -lsaymak için bunu aktarabilirsiniz .


Birlikte çalışmamın nedeni comm, dosyalar sıralandığında, yan yana karşılaştırmanın hesaplamalı olarak gerçekten basit olmasıdır. Milyonlarca insanla uğraşıyorsanız, bu bir fark yaratacaktır.

Bu birkaç sahte dosya ile gösterilebilir. Oldukça hızlı bir bilgisayarım var, bu yüzden yaklaşımlar arasındaki farkı göstermek için oldukça mamut örnek setine ihtiyacım var. Dosya başına 10 milyon 10 karakterlik dizeye gittim.

$ 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

Sıralama benim için çoğu zaman gereken şeydir. Abc.txt dosyasının statik olduğunu iddia edersek, önceden sıralayabiliriz ve bu da gelecekteki karşılaştırmaları çok daha hızlı yapar:

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

Bunlara bakıp birkaç saniye ilgisiz olduğunu düşünebilirsiniz, ancak bunların üst düzey bir makinede çalıştığını vurgulamak zorundayım. Bunu (örneğin) bir Raspberry Pi 3 üzerinde yapmak istiyorsanız, çok daha yavaş dönüşlere bakacaksınız ve fark gerçekten önemli olan bir noktaya yükselecektir.


7

bir liste almak için:

grep -Fwf abc.txt mno.txt

size benzer bir şey verir:

abcd
abcd
zef

sadece benzersiz bir liste almak istiyorsanız, o zaman aşağıdaki gibi kullanın:

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

ve sayıları elde etmek için:

grep -Fcwv -f abc.txt mno.txt

  • -F şu anlama gelir: PATTERN'yi normal ifadeler yerine sabit dizelerin listesi olarak yorumlama.
  • -folacak olan FILE'den desen elde eder abc.txt.
  • Biz içine bakmak mno.txtkalıpları için
  • -c Eşleşme sayısını sayın
  • -wYalnızca "tam kelimeler" için arama yapın: eşleşen alt dize satırın başında olmalı veya öncesinde kelime içermeyen bir karakter olmalıdır. Benzer şekilde, ya satırın sonunda olmalı ya da sözcük olmayan bir kurucu karakter olmalıdır. Kelime oluşturucu karakterler harfler, rakamlar ve alt çizgidir.
  • -v Aramayı geri al

1
OP bir istiyorsa sayımı ait olmayan maçları, daha fazla gibi olmaması gerektiğini grep -cxvFf abc.txt mno.txt?
steeldriver

Sadece gördüm: D ... beni kurtarmak için her zaman buradasın: D
Ravexina

FYI fgrep, egrepalternatifler sözde itiraz edilir (lehine grep -F, grep -E- kimse hiç gidecek inanıyor emin değilim
steeldriver

-xKullanırken kullanmak gerekli -Fmi?
Ravexina

1
OP'nin tam olarak neyi saymak istediğine bağlıdır - örneğin mno.txt abcdefbir eşleşme veya eşleşmeme olarak sayılmalı abcdmı?
steeldriver

3

İşi yapmak için awk'yi, önce desen dosyasını, sonra kontrol etmek istediğimiz dosyayı iki dosya geçirerek kullanabiliriz. İlk dosyayı okurken, NR==FNRsatırları diziye okuyabileceğimizi biliyoruz . Ne zaman NR!=FNRböyle bir hat için dizi ayarlanmış olup olmadığını kontrol ederiz.

$ 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

Tersine, içinde olmayan çizgileri yazdırmak için deseni reddedebiliriz abc.txt

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

Ve istihdam edebileceğimiz kişilerin sayısını yazdırmak istiyorsak sortve wc:

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

Sanırım yanlış yöne sahipsin. Bildiğim kadarıyla ben soruyu anlamadım olarak, OP kümesi farkı (boyutunu) hesaplamak istiyor abc.txt- mno.txtolduğunu {xyz, pqrs}.
David Foerster

2

Sözcük listelerinden herhangi biri sıralanmamışsa, ortak sözcükleri hatırlamak için etkin bir veri kümesi yapısı kullanmak daha hızlı olur.

piton

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

Kullanımı:

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

Python (daha verimli)

Ara depolama ve çalışma süresi için biraz bellek kaydetmek istiyorsanız, bunu anlamak biraz daha zor programı kullanabilirsiniz:

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

Verim

Verilen abc.txtve mno.txther biri 10 rasgele ASCII basamaklı karakterin 1 mio ayrılmamış satırı ile (kurulum için Oli'nin cevabına bakınız):

$ 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

toplam: 23 saniye

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.