Альтернатива zip () для итерации двух итераций - PullRequest
13 голосов
/ 24 февраля 2010

У меня есть два больших (~ 100 ГБ) текстовых файла, которые должны проходить одновременно.

Zip хорошо работает для небольших файлов, но я обнаружил, что он на самом деле составляет список строк из моих двух файлов. Это означает, что каждая строка хранится в памяти. Мне не нужно ничего делать со строками более одного раза.

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.

Есть ли альтернатива zip (), которая действует как генератор, который позволит мне перебирать эти два файла без использования> 200 ГБ оперативной памяти?

Ответы [ 4 ]

22 голосов
/ 24 февраля 2010

itertools имеет функцию izip, которая делает это

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

Если файлы разных размеров, вы можете использовать izip_longest, так как izip остановится на меньшем файле.

15 голосов
/ 24 февраля 2010

Вы можете использовать izip_longest , например, для заполнения более короткого файла пустыми строками

в Python 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=""):
            ...

или Python 3 +

from itertools import zip_longest
with handle1 as open('filea', 'r'), handle2 as open('fileb', 'r'): 
    for i, j in zip_longest(handle1, handle2, fillvalue=""):
        ...
0 голосов
/ 24 февраля 2010

Если вы хотите укоротить до самого короткого файла:

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()

Или

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 голосов
/ 24 февраля 2010

Как то так? Словесно, но, похоже, это то, что вы просите.

Его можно настроить так, чтобы он выполнял такие вещи, как правильное слияние для сопоставления ключей между двумя файлами, что часто является более необходимым, чем упрощенная функция zip. Кроме того, это не усекает, что делает алгоритм SQL OUTER JOIN, опять же, отличается от того, что делает zip и более типично для файлов.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...