ค้นหา ID ในไฟล์เดียวที่ไม่ได้อยู่ในอีกไฟล์


9

ฉันมีสองไฟล์:

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • ฉันต้องการตรวจสอบว่า "abcd" มีอยู่ในไฟล์mno.txtหรือไม่
  • มันไม่จำเป็นว่าถ้า "ABCD ให้" เป็นครั้งแรกในabc.txtก็จะยังเป็นครั้งแรกในmno.txt
  • มี ID ดังกล่าวหลายพันรายการในทั้งสองไฟล์
  • ฉันต้องการที่จะตรวจสอบวิธีการหลาย id ของไม่ได้อยู่ในmno.txtที่อยู่ในabc.txt

ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


19

หากเป้าหมายของคุณคือการค้นหาบรรทัดทั่วไปหรือผิดปกติcommคำสั่งของฉันจะไปที่นี่

มันเปรียบเทียบสองไฟล์และรายการ - ในสามคอลัมน์ - บรรทัดที่ไม่ซ้ำกับไฟล์ 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 คุณจะต้องดูการหยุดซ่อมบำรุงที่ช้ากว่ามากและความแตกต่างจะเพิ่มขึ้นจนถึงจุดที่สำคัญจริงๆ


7

เพื่อรับรายการ:

grep -Fwf abc.txt mno.txt

มันให้สิ่งที่คล้ายกับคุณ:

abcd
abcd
zef

หากคุณต้องการได้รับรายการที่ไม่ซ้ำกันให้ใช้มันเช่น:

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

และเพื่อให้ได้จำนวน:

grep -Fcwv -f abc.txt mno.txt

  • -F หมายถึง: ตีความรูปแบบเป็นรายการของสตริงคงที่แทนการแสดงออกปกติ
  • -fabc.txtได้รับรูปจากแฟ้มที่จะเป็น
  • เรามองหาmno.txtรูปแบบ
  • -c นับจำนวนแมตช์
  • -wค้นหาเฉพาะ "คำทั้งหมด": สตริงย่อยที่ตรงกันต้องอยู่ที่จุดเริ่มต้นของบรรทัดหรือนำหน้าด้วยอักขระที่ไม่ใช่คำ ในทำนองเดียวกันจะต้องอยู่ที่ท้ายบรรทัดหรือตามด้วยอักขระที่ไม่ใช่คำ อักขระที่เป็นองค์ประกอบของ Word คือตัวอักษรตัวเลขและขีดล่าง
  • -v ย้อนกลับการค้นหา

1
ถ้า OP ต้องการจำนวนการจับคู่ที่ไม่ตรงกันนั่นจะไม่เป็นเช่นนั้นgrep -cxvFf abc.txt mno.txtหรือ
ขับเหล็ก

เพิ่งเห็นมัน: D ... คุณอยู่ที่นี่เสมอเพื่อช่วยฉัน: D
Ravexina

FYI fgrep, egrepสลับเลิกคาดคะเน (ในความโปรดปรานของgrep -F, grep -E- แม้ว่าผมไม่แน่ใจว่าทุกคนเชื่อว่าพวกเขาเคยจะหายไป
steeldriver

จำเป็นต้องใช้-xเมื่อใช้-Fหรือไม่?
Ravexina

1
มันขึ้นอยู่กับสิ่งที่ OP ต้องการที่จะนับว่า - เช่นถ้ามี mno.txt abcdefควรนับว่าเป็นคู่หรือไม่ใช่ตรงกับabcd?
ขับเหล็ก

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

ฉันคิดว่าคุณมีวิธีที่ผิด เท่าที่ผมเข้าใจคำถาม, OP ต้องการในการคำนวณ (ขนาด) ความแตกต่างของชุดabc.txt- ซึ่งเป็นmno.txt {xyz, pqrs}
David Foerster

2

หากรายการคำใดคำหนึ่งไม่ได้เรียงลำดับจะเป็นการเร็วกว่าที่จะใช้โครงสร้างข้อมูลชุดที่มีประสิทธิภาพเพื่อจดจำคำศัพท์ทั่วไป

หลาม

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

Python (มีประสิทธิภาพมากขึ้น)

หากคุณต้องการประหยัดหน่วยความจำเล็กน้อยสำหรับการจัดเก็บตัวกลางและเวลาทำงานคุณสามารถใช้โปรแกรมที่เข้าใจยากขึ้นเล็กน้อย:

#!/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 ไม่เรียงลำดับบรรทัดของอักขระ ASCII แบบสุ่ม 10 ตัวแต่ละตัว (ดูคำตอบของ Oli สำหรับการตั้งค่า):

$ time python3 set-difference.py abc.txt mno.txt
user    0m10.453s

เมื่อเทียบกับ

$ 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 วินาที

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.