zip (* [iter (s)] * n)은 파이썬에서 어떻게 작동합니까?


103
s = [1,2,3,4,5,6,7,8,9]
n = 3

zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]

어떻게 zip(*[iter(s)]*n)작동합니까? 좀 더 자세한 코드로 작성했다면 어떤 모습일까요?


1
또한 어떻게 작동하는지 여기에서 설명합니다 : stackoverflow.com/questions/2202461/…
Matt Joiner

여기에 답변이 충분하지 않다면 여기에 블로그를 게시
telliott99

7
매우 흥미롭지 만이 기술은 파이썬의 핵심 "가독성"가치에 반해야합니다!
Demis

답변:


108

iter()시퀀스에 대한 반복자입니다. 수량을 [x] * n포함하는 목록 , 즉 각 요소가있는 길이 목록을 생성합니다 . 함수 호출을 위해 시퀀스를 인수로 압축 해제합니다. 따라서 동일한 반복기를에 3 번 전달하고 매번 반복기에서 항목을 가져옵니다.nxnx*argzip()

x = iter([1,2,3,4,5,6,7,8,9])
print zip(x, x, x)

1
알아두면 좋은 점 : 반복자 가 항목을 yields (= returns) 할 때이 항목을 "소비 된"것으로 상상할 수 있습니다. 따라서 다음에 반복자가 호출되면 다음 "사용되지 않은"항목이 생성됩니다.
winklerrr

46

다른 훌륭한 답변과 주석은 인수 압축 해제zip () 의 역할을 잘 설명합니다 .

으로 이그나시오ujukatzel 말하자면, 당신은에 전달 zip()같은 반복자 세 참조와 zip()주문의 반복자에 대한 각 참조에 정수-의 3 튜플한다 :

1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9
^                    ^                    ^            
      ^                    ^                    ^
            ^                    ^                    ^

그리고 더 자세한 코드 샘플을 요청했기 때문에 :

chunk_size = 3
L = [1,2,3,4,5,6,7,8,9]

# iterate over L in steps of 3
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x
    end = start + chunk_size
    print L[start:end] # three-item chunks

start및 의 값을 따릅니다 end.

[0:3) #[1,2,3]
[3:6) #[4,5,6]
[6:9) #[7,8,9]

FWIW, 다음 map()과 같은 초기 인수를 사용 하여 동일한 결과를 얻을 수 있습니다 None.

>>> map(None,*[iter(s)]*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

에 대한 자세한 내용 zip()map(): http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/


31

모든 답변에서 놓친 것 (반복자에 익숙한 사람들에게는 분명 할 것임)이 있지만 다른 사람들에게는 그렇게 분명하지 않은 것은 다음과 같습니다.

동일한 이터레이터가 있기 때문에 소비되고 나머지 요소는 zip에서 사용됩니다. 그래서 우리가 단순히 목록을 사용하고 iter를 사용하지 않는다면.

l = range(9)
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate 
# output 
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)]

반복자를 사용하여 값을 팝하고 사용 가능한 상태 만 유지하므로 zip의 경우 0이 소비되면 1을 사용할 수 있고 2를 계속 사용할 수 있습니다. 매우 미묘하지만 아주 영리합니다 !!!


+1, 당신은 나를 구했습니다! 나는 모든 사람들이 이것을 알고 있다고 가정하고 다른 답변 이이 중요한 세부 사항을 건너 뛰었다는 것을 믿을 수 없습니다. 이 정보가 포함 된 문서에 대한 참조를 제공 할 수 있습니까?
Snehasish Karmakar

9

iter(s) s에 대한 반복자를 반환합니다.

[iter(s)]*n s에 대해 동일한 반복기의 n 배 목록을 만듭니다.

따라서를 수행 할 때 zip(*[iter(s)]*n)목록에서 세 개의 반복자 모두에서 항목을 순서대로 추출합니다. 모든 이터레이터는 동일한 객체이기 때문에 목록을 n.


7
'n 개의 동일한 목록의 반복자'가 아니라 'n 개의 동일한 반복기 객체'. 다른 반복기 객체는 동일한 목록에 있더라도 상태를 공유하지 않습니다.
Thomas Wouters

감사합니다. 사실 그것은 내가 "생각하고있는"것이었지만 다른 것을 썼다.
sttwister 2010

6

이런 식으로 zip을 사용하는 것에 대한 조언 한마디. 길이가 균등하게 나눌 수 없으면 목록이 잘립니다. 이 문제를 해결하려면 채우기 값을 허용 할 수있는 경우 itertools.izip_longest 를 사용할 수 있습니다. 또는 다음과 같이 사용할 수 있습니다.

def n_split(iterable, n):
    num_extra = len(iterable) % n
    zipped = zip(*[iter(iterable)] * n)
    return zipped if not num_extra else zipped + [iterable[-num_extra:], ]

용법:

for ints in n_split(range(1,12), 3):
    print ', '.join([str(i) for i in ints])

인쇄물:

1, 2, 3
4, 5, 6
7, 8, 9
10, 11

3
이것은 이미 itertools레시피에 문서화되어 있습니다 : docs.python.org/2/library/itertools.html#recipes grouper . 바퀴 재발견 할 필요가 없습니다
jamylak

1

파이썬 인터프리터에서 어떤 일이 일어나고 있는지 보는 것이 더 쉬울 것 ipython입니다 n = 2.

In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]

따라서 동일한 반복기 객체를 가리키는 두 개의 반복기 목록이 있습니다. iter객체에서 반복자 객체를 반환하고이 시나리오에서는 *2파이썬 구문 설탕 으로 인해 동일한 반복자가 두 번 임을 기억하십시오 . 반복기는 한 번만 실행됩니다.

또한, zip반복 가능한 개수 ( 시퀀스반복 가능 )를 취하고 각 입력 시퀀스의 i 번째 요소에서 튜플을 생성합니다. 우리의 경우 두 반복자가 동일하기 때문에 zip은 출력의 각 2 요소 튜플에 대해 동일한 반복기를 두 번 이동합니다.

In [41]: help(zip)
Help on built-in function zip in module __builtin__:

zip(...)
    zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

    Return a list of tuples, where each tuple contains the i-th element
    from each of the argument sequences.  The returned list is truncated
    in length to the length of the shortest argument sequence.

풀고 ( *) 연산자 보장 반복자이 경우 2 소자 터플을 생성하기에 충분한 입력이 없을 때까지이다 소진 실행할 것이다.

이것은의 값으로 확장 할 수 있습니다 nzip(*[iter(s)]*n)설명 된대로 작동합니다.


느려서 죄송합니다. 그러나 "* 2 파이썬 구문 설탕으로 인해 동일한 반복자가 두 번 나타납니다. 반복자도 한 번만 실행됩니다." 부분 제발? 그렇다면 결과가 [( "A", "A") ....]가 아닌 이유는 무엇입니까? 감사.
Bowen Liu

@BowenLiu *는 객체를 복제하는 데 편리합니다. 스칼라로 시도한 다음 목록으로 시도하십시오. 또한 시도 print(*zip(*[iter("ABCDEFG")]*2))print(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")])). 그런 다음 두 명령문에서 실제로 반복기 객체가 무엇인지 확인하기 위해 두 단계를 더 작은 단계로 분해하기 시작합니다.
akhan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.