2010-02-24 4 views
11

두 개의 큰 (~ 100 GB) 텍스트 파일이 동시에 반복되어야합니다.두 개의 반복 가능을 반복하는 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. 

나 램의> 사용하지 않고이 두 파일을 통해 2백기가바이트을 반복 할 수는 발전기 역할을 우편()에 대한 대안이 있는가?

+0

... 사실, 나는 한 가지 방법을 알고 있지만 매우 pythonic하지 않습니다 .- line1 : line1 = handle1.readline(); line2 = handle2.readline(); 당신이 찾을 수있는 1 호선과 2 호선 뭔가 ... 메모리 제약 환경의 –

+0

말하기를 않는이 흥미 http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit-integers-in-2mb.html –

답변

20

itertools은 파일 크기가 다른 경우에는 작은 파일에서 중지됩니다 izip로, izip_longest 사용할 수 있습니다

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

것을 수행하는 기능 izip 있습니다.

-1

이와 비슷한? 글쎄,하지만 네가 요구하는 것 같아.

단순한 우편 기능보다 필요한 것보다 종종 두 파일 사이의 키에 맞게 적절한 병합 같은 일을 조정할 수 있습니다. 또한, 이것은 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 
+3

'if1_more 또는 if2_more :'라고 말하지 않았습니까? 그리고 왜 파일이 ​​이미 iters 일 때 iter에서 file1과 file2를 랩합니까? 그리고 마지막으로, 이것은 단지 학문적 인 것이 었습니다. "해야만한다면 어떻게 할 수 있겠습니까?" 운동? 물론 똑같은 일을하는 20 줄짜리 코드를 작성하는 대신에 std lib의 itertools 모듈에서 izip이나 izip_longest를 사용하는 것을 선호하지만, 유지 관리되고 지원 (디버깅되어야합니다!)해야합니다. – PaulMcG

+0

@Paul McGuire : 예, 맞습니다.명시 적 iter는 다음을 사용하고 EOF에서 적절한 StopIteraction 예외를 가져와야합니다. 이것은 "학문적 인"것이 아닙니다. 이것은 질문에 대한 대답입니다. 문제는 모호하며 itertools가 필요한 기능을 제공하지 않을 수 있습니다. 이것은 어느 쪽이든일지도 모르지만, 이것은 맞출 수 있습니다. –

+0

Py2.5.4를 실행 중이며 파일 끝에있는 파일 객체에서'next()'를 호출하면 StopIteration이 발생합니다. – PaulMcG

0

: 그렇지

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

두 파일의 길이가 다른 경우? 짧은 문자는 잘립니다. 바라건대, 그것은 바람직한 행동입니다. –

+0

@ S.Lott :''zip'은 무엇을합니까? – voyager

+0

@ S.Lott - 이것은 i_ended와 j_ended가 모두 while-forever 루프에서 빠져 나오기 때문에 긴 파일의 끝까지 읽힐 것입니다. 그러나 확실히 개선의 여지가 있습니다. 한 파일이 다른 파일보다 훨씬 짧으면 현재 코드가 .next()를 호출하고 StopIteration *을 여러 번 catch합니다. 'if if i_ended : try : i = handel1.next() ...'(if if1_more :'코드에서와 같이) 할 수있을만큼 간단합니다. (Ah! 나는 당신의 코멘트가 편집 된 버전이 아니라 원래의 코드에 응답했다는 것을 안다.) – PaulMcG

14

당신은 패드에이 같은 izip_longest을 사용할 수 있습니다짧은 파이썬 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=""): 
      ... 

에 빈 줄

와 파일이나 python3.1 python3를 들어

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 with'with' - 들여 쓰기 레벨을 낮추기 위해 Py3.1 구문을 좋아합니다. – PaulMcG

0

으로는, izip_longest 실제로 zip_longest입니다.

from itertools import zip_longest 

for i, j in izip(handle1, handle2): 
    ... 
관련 문제