2016-04-02 6 views
4

Also jetzt habe ich 4 if/elif/else-Anweisungen fest codiert. Gibt es dort einen dynamischeren Weg dies zu tun? Zum Beispiel, wenn ich eine 10 oder Eve 40 Fusion machen wollte?Gibt es eine Möglichkeit, diese "n-way merge" in Python zu vereinfachen

#4-way merge sort, sorted page files 
outfile="fullsorted.txt" 
of=open(outfile,"w") 
f1=open("temp0-sorted.txt","r") 
f2=open("temp1-sorted.txt","r") 
f3=open("temp2-sorted.txt","r") 
f4=open("temp3-sorted.txt","r") 

f1_line=f1.readline() 
f2_line=f2.readline() 
f3_line=f3.readline() 
f4_line=f4.readline() 

while len(f1_line)>0 and len(f2_line)>0 and len(f3_line)>0 and len(f4_line)>0: 
    if f1_line < f2_line and f1_line < f3_line and f1_line < f4_line and len(f1_line)>0: 
    of.write(f1_line) 
    f1_line=f1.readline() 
    elif f2_line < f3_line and f1_line < f4_line and len(f2_line)>0: 
    of.write(f2_line) 
    f2_line=f2.readline() 
    elif f3_line < f4_line and len(f3_line)>0: 
    of.write(f3_line) 
    f3_line=f3.readline() 
    else: 
    of.write(f4_line) 
    f4_line=f4.readline() 

of.close() 
+1

Stellen Sie sich zunächst eine Liste vor: 'l = [f1, f2, f3 ...]'. – user2864740

+0

@DSM: Benötigt kein modernes Python; 'heapq.merge' gibt es seit 2.6. – ShadowRanger

+0

@ShadowRanger: ah, du hast Recht! Was die Vereinfachung anbelangt, wird dies wahrscheinlich die beste sein. – DSM

Antwort

1

mit Ihren eigenen Code-Mustern, erweitern und zu einem listenbasierten Ansatz wie folgt aus:

outfile="fullsorted.txt" 
of=open(outfile,"w") 
files = ["temp0-sorted.txt", "temp1-sorted.txt","temp2-sorted.txt","temp3-sorted.txt"] 

filehandles = [open(f, "r") for f in files] 

lines = [f.readline() for f in filehandles] 

while len(filehandles) > 0: 
    smallest = min(lines) 
    smallestposition = lines.index(smallest) 
    of.write(smallest) 
    lines[smallestposition] = filehandles[smallestposition].readline() 
    if lines[smallestposition] == "": 
     filehandles[smallestposition].close() 
     filehandles.pop(smallestposition) 
     lines.pop(smallestposition) 

of.close() 

Beachten Sie, dass dies die gesamten Zusammenführen von Dateien, anstatt zu stoppen, sobald eine Datei abläuft .

5

Verwenden Sie einfach heapq.merge:

import heapq 

#4-way merge sort, sorted page files 
outfile="fullsorted.txt" 

with open("temp0-sorted.txt","r") as f1,\ 
    open("temp1-sorted.txt","r") as f2,\ 
    open("temp2-sorted.txt","r") as f3,\ 
    open("temp3-sorted.txt","r") as f4,\ 
    open(outfile,"w") as of: 
    of.writelines(heapq.merge(f1, f2, f3, f4)) 
+0

Ich versuche, es ohne eine eingebaute merge-Funktion zu tun, danke für diesen Tipp (Auch die Dateien sind zu groß für den Speicher, also lese ich sie 1 Zeile zu einer Zeit) –

+0

@TomFranks: 'heapq. merge "ist eine generator-Funktion (liest ihre Eingaben träge und schreibt sie träge; sie ist überraschend ähnlich geschrieben wie der Code, den sie schreiben), und' writelines' schreibt träge, so dass Speicher hier kein Thema ist. – ShadowRanger

0

Vielen Dank für die Tipps alle, hier ist meine Lösung:

sorted_files=[] 

strings=[] 
for i in xrange(files+1): 
    sorted_files.append(open("temp"+str(i)+"-sorted.txt","r")) 
    strings.append(sorted_files[i].readline()) 

print len(sorted_files) 
print strings 
eofs=0 
while eofs != 1: 
    small_str=min(filter(lambda x: x != "", strings)) 
    str_index=strings.index(small_str) 
    of.write(small_str) 
    strings[str_index]=sorted_files[str_index].readline() 
    if all(i =="" for i in strings): 
    eofs=1 

Als Benchmark ich dies mit rund 6,5 Millionen Zeilen in einer Datei geprüft (~ 700 MB) Sie paginieren sie in 500.000 Zeilen, sortieren sie dann in lexikographischer Reihenfolge und sortieren sie (genau zusammengeführt) mit dem obigen Code, so dass ungefähr 128 Dateien zusammengeführt wurden (ich hatte versehentlich eine 2 Milliarden Zeilen Datei) löschte es, beim Löschen der Seiten Dateien), ein d es die Datei sortiert und gefundenen Duplikate in 16 min:

real 15m54.375s 
user 15m52.096s 
sys 0m3.000s 

Das war mein erstes Skript dieser Art würde ich mich sehr freuen, wenn Sie mir etwas Futter geben könnte zurück, als ob die Seitengröße war angemessen, und ob die verwendeten Sortiermethoden korrekt waren. Die Seitendateien wurden schnell generiert und sortiert, jedoch am meisten zusammengeführt.

+0

Sie können problemlos mit verschiedenen Seitengrößen experimentieren und die Details selbst veröffentlichen. Es wäre auch nützlich, es separat mit einem Lauf zu vergleichen, der die eingebaute heapq.merge verwendet. Ich vermute, dass das temporäre Paging im Speicher (StringIO) die meisten Vorteile bringt. Führen Sie einfach einen Profiling-Lauf durch und sehen Sie sich die Ergebnisse an. Warum bitten Sie andere zu spekulieren, wenn Sie die Ergebnisse auf Ihrer Maschine selbst leicht bestimmen können? –

+0

kann ich begrenzt für das Testen mit jetzt, IE tun, ich habe nur 1 Dateigröße, die groß ist. Und # 2, es gibt wahrscheinlich einen besseren Weg, es zu programmieren, um es effizienter zu machen, wie ich sagte, das war mein erstes Programm. Hier sind die Ergebnisse aus, dass: Ergebnisse auf eine Datei mit 64 Millionen Strings: * 500000 Linie Seite Dateien (128 Dateien) = 15 min 46 sec * 1000000 Linie Auslagerungsdateien (64 Dateien) = 11 min 19 sec * 2500000 Zeilendateien (26 Dateien) = 8 Min. 28 Sek. * 8000000 Zeilendateien (8 Dateien) = 7 Min. 49 Sek. * 16000000 Zeilendateien (4 Dateien) = 7 Min. 58 Sek –

Verwandte Themen