2010-02-24 19 views
11

Eşzamanlı olarak yinelenmesi gereken iki büyük (~ 100 GB) metin dosyam var.İki yinelenen ile yineleme için zip() alternatifi

Zip, daha küçük dosyalar için iyi çalışıyor ancak aslında iki dosyadan bir satır listesi oluşturduğunu öğrendim. Bu, her satırın hafızada saklandığı anlamına gelir. Hatlarla bir kereden fazla bir şey yapmam gerekmiyor.

handle1 = open('filea', 'r'); handle2 = open('fileb', 'r') 

for i, j in zip(handle1, handle2): 
    do something with i and j. 
    write to an output file. 
    no need to do anything with i and j after this. 

bana ram> kullanmadan bu iki dosyalar arasında 200 GB yineleme sağlayacak bir jeneratör görevi gören zip() bir alternatif var mı?

+0

... aslında, bir yol biliyorum ama çok pythonic görünmüyor - line1: line1 = handle1.readline(); line2 = handle2.readline(); line1 ve line2 ile bir şeyler yapın ... –

+0

Hafıza kısıtlı ortamlardan bahsetmişken bu ilginç http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit-integers-in-2mb.html –

cevap

20

itertools dosyaları farklı boyutlarda ise daha küçük dosyaya duracaktır izip olarak, izip_longest kullanabilir

from itertools import izip 
for i, j in izip(handle1, handle2): 
    ... 

bunu yapmaz bir işlevi izip sahiptir.

-1

Böyle bir şey mi var? Wordy, ama istediğin gibi görünüyor.

Bu, basit zip işlevinden daha fazla ihtiyaç duyulan iki dosya arasındaki anahtarları eşleştirmek için uygun birleştirme gibi şeyler yapmak için ayarlanabilir. Ayrıca, bu, SQL OUTER JOIN algoritmasının, zip'ten ne kadar farklı ve daha tipik dosyalardan farklı olduğunu da kesmez. En kısa dosyaya kesmek istiyorsanız

with open("file1","r") as file1: 
    with open("file2", "r" as file2: 
     for line1, line2 in parallel(file1, file2): 
      process lines 

def parallel(file1, file2): 
    if1_more, if2_more = True, True 
    while if1_more or if2_more: 
     line1, line2 = None, None # Assume simplistic zip-style matching 
     # If you're going to compare keys, then you'd do that before 
     # deciding what to read. 
     if if1_more: 
      try: 
       line1= file1.next() 
      except StopIteration: 
       if1_more= False 
     if if2_more: 
      try: 
       line2= file2.next() 
      except StopIteration: 
       if2_more= False 
     yield line1, line2 
+3

'While if1_more VEYA if2_more:' demek istemedin mi? Ve dosyalar zaten iters neden dosya1 ve dosya2 iters, neden sarın? Ve son olarak, bu sadece bir akademisyen miydi? Bunu yapmak zorunda kalırsam kendim için bunu nasıl yapardım? egzersiz? Şüphesiz, aynı şeyi yapan 20 satır homebrewed kod yazmak yerine, izip veya izip_longest'i std lib'deki itertools modülünden kullanmayı tercih eder, ancak aynı şeyi yapan, ancak desteklenmeli ve desteklenmelidir (ve hata ayıklanmalıdır!). – PaulMcG

+0

@Paul McGuire: Evet, OR doğru.Açık olan iter, daha sonra kullanmak ve EOF'ta uygun bir StopEteraction istisnası almak için gereklidir. Hayır, bu "akademik" değildi. Bu sorunun bir cevabı. Soru belirsiz ve itertools gerekli özellikleri sağlayamıyor olabilir. Bu da olmayabilir, ancak bu uyarlanabilir. –

+0

Py2.5.4 çalıştırıyorum ve dosyanın sonunda bir dosya nesnesinde 'next()' yi çağırıyorum, StopIteration'ı benim için yükseltir. – PaulMcG

0

: Else

handle1 = open('filea', 'r') 
handle2 = open('fileb', 'r') 

try: 
    while 1: 
     i = handle1.next() 
     j = handle2.next() 

     do something with i and j. 
     write to an output file. 

except StopIteration: 
    pass 

finally: 
    handle1.close() 
    handle2.close() 

handle1 = open('filea', 'r') 
handle2 = open('fileb', 'r') 

i_ended = False 
j_ended = False 
while 1: 
    try: 
     i = handle1.next() 
    except StopIteration: 
     i_ended = True 
    try: 
     j = handle2.next() 
    except StopIteration: 
     j_ended = True 

     do something with i and j. 
     write to an output file. 
    if i_ended and j_ended: 
     break 

handle1.close() 
handle2.close() 

Ya

handle1 = open('filea', 'r') 
handle2 = open('fileb', 'r') 

while 1: 
    i = handle1.readline() 
    j = handle2.readline() 

    do something with i and j. 
    write to an output file. 

    if not i and not j: 
     break 
handle1.close() 
handle2.close() 
+0

Ve iki dosya farklı uzunluklarda mı? Bu kısa olanı keser. Umarım istenen davranış budur. –

+0

@ S.Lott: "zip" nin yaptığı şey değil mi? – voyager

+0

@ S.Lott - bu, hem i_ended AND j_ended olduğunda, hem forever hem de daha uzun dosya sonuna kadar okuyacaktır. Ama kesinlikle iyileştirme için yer var. Bir dosya diğerinden daha kısasa, mevcut kod, dosyanın bittiğini öğrenmiş olduğumuzda .next() öğesini çağırır ve StopIteration * çok kez * yakalar. Yeterince basit: 'i_ended değilse: try: i = handel1.next() ...' (eğer if (if if1_more: 'code) 'da yaptığınız gibi. (Ah! Görüntün orijinal koduna cevap verdiğini görüyorum, düzenlenmiş versiyonu değil - üzgün olduğu için üzgünüm!) – PaulMcG

14

Sen pad için böyle izip_longest kullanabilirsinizkısa piton 2,6

from itertools import izip_longest 
with handle1 as open('filea', 'r'): 
    with handle2 as open('fileb', 'r'): 
     for i, j in izip_longest(handle1, handle2, fillvalue=""): 
      ... 

boş hatlar

ile dosya veya python3.1 python3 için

from itertools import izip_longest 
with handle1 as open('filea', 'r'), handle2 as open('fileb', 'r'): 
    for i, j in izip_longest(handle1, handle2, fillvalue=""): 
     ... 
+0

+1 - Girinti seviyelerini korumak için Py3.1 sözdizimini seviyorum. – PaulMcG

0

yılında, izip_longest aslında zip_longest olduğunu.