2016-07-10 18 views
1

Ich habe 2 Datei: Datei A enthält 200 000 Zeilen; Datei B enthält 4 000 000 Zeilen. Also, ich möchte diese Dateien vergleichen und die Zeilen drucken, die nicht in Datei B sindPython: Der beste Weg, um 2 Textdateien zu vergleichen?

Zum Beispiel: Datei A:

1 
    2 
    3 

Datei B:

1 
    4 
    5 
    6 
    7 

Der Ausgang :

2 
    3 

Und das unten ist mein Code:

Dieser Code funktioniert, es dauert jedoch sehr lange. Also, wie beschleunigt man den Code-Prozess?

Jede Hilfe wird sehr geschätzt! :)

+1

Haben Sie das sah in [ 'filecmp' Modul] (https : //docs.python.org/3/library/filecmp.html)? – karthikr

+0

Dies ist ein klassisches Beispiel für [asymptotische Komplexität] (https://en.wikipedia.org/wiki/Asymptotic_computational_complexity), allgemein bekannt als [Große O-Notation] (https://en.wikipedia.org/wiki/Big_O_notation)).Die 'not in'-Anweisung muss die ganze Datei jedes Mal lesen, das ist O (n) (lineare Zeit - die Menge an Arbeit ist proportional zur Länge der Eingabe). Da Sie dies für jede Zeile in der ersten Datei einmal aufrufen, machen Sie diese lineare Menge an Arbeit eine lineare (O (n)) Anzahl von Malen. Als Ergebnis benötigt Ihr Algorithmus O (n) x O (n) oder O (n^2) Zeit, um zu laufen - auch bekannt als quadratische Zeit. – dimo414

Antwort

2

einen Satz erstellen gerade von:

with open('C:/A.txt') as a: 
    with open('C:/B.txt') as b: 
     lines = set(b) 
    for line in a: 
     if line not in lines: 
      print(line) 

Vielleicht ein besserer Weg, so etwas wie dieses würde die Hashes der Zeilen in Datei B - und vergleichen Sie die Zeilen in A mit denen in diesem Satz -

Solch ein Set dauert etwa hundert Megabyte Speicher, sollte daher in den Speicher in einem Notebook oder wo passen rkstation:

linesB = {hash(line) for line in open("fileB"))} 
for line in open("fileA"): 
    if hash(line) not in linesB: 
     print (line) 

Die Haupt Geschwindigkeit hier oben ist, dass für eine Linie linear innerhalb fileB im Gegensatz zu suchen, ist es nur einmal gelesen wird - und jede Zeile in einem Satz zur Verfügung gestellt, die eine konstante Look-up-Zeit hat. Daher kommen Sie von ~ 200.000 X 4.000.000 Vergleichen (O (m X n)) auf nur ~ 200.000 Vergleiche (O (m X 1)) herunter.

Das nicht zu schweigen von der Notwendigkeit, Daten aus dem filsystem 200.000 mal in den Programmspeicher zu verschieben.

Indem Sie nur die hash Zeilen in B behalten Sie vermeiden, alle Textinformationen von DateiB im Speicher zu behalten - nur 24 Bytes für jeden Hash (in einem 64-Bit-System) - anstelle der Textinformation selbst (die von jedem abhängt Zeilenlänge) + sein Hash.

+0

Danke, dass Sie mir den Code gegeben haben. Nach der Verwendung von Hash, läuft der Code sehr schnell :) – NGuyen

+0

Was es schnell geht, ist nltthe 'hash' - liest die zweite Datei nur einmal und legt sie in ein' set', das eine konstante Nachschlagezeit hat. – jsbueno

+0

Es gibt keine Garantie, dass zwei verschiedene Zeilen nicht auf den gleichen Wert synchronisiert werden, insbesondere wenn die Zeilenlänge zunimmt. Angesichts der standardmäßigen Hash-Randomisierung von Strings ist dies zwischen Läufen nicht einmal deterministisch. Für eine Garantie müssen Sie die Zeichenfolgen selbst zur Gruppe hinzufügen (wird bei einer Hash-Kollision in die Hash-Tabelle eingefügt), was die Speicheranforderungen stark erhöht. – eryksun

1

Ein schneller Weg wäre, um die Datei einmal zu öffnen und einen Satz verwenden:

with open('C:/A.txt') as a, open('C:/B.txt') as b: 
    lines = set() 
    for line in a: 
     if line not in lines: 
      for line_b in b: 
       lines.add(line_b) 
       if line_b == line: 
        break 
      else: 
       print(line) 
1

Sie könnten die Operation set difference verwenden, um alle Zeilen zu erhalten, die in diesen Dateien nicht übereinstimmen.

with open('A.txt') as a: 
    contentA = set(a) 

with open('B.txt') as b: 
    contentB = set(b) 

print(contentA - contentB) 

Edit: Der umgekehrte Vorgang, den Inhalt der Datei B zu drucken, die jetzt nicht mehr in A sind nur

print(contentB - contentA)

Verwandte Themen