web-dev-qa-db-ja.com

PythonでZip(* [iter(s)] * n)はどのように機能しますか?

_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)はどのように機能しますか?より冗長なコードで記述された場合、どのようになりますか?

92
Oliver Zheng

iter() は、シーケンスの反復子です。 _[x] * n_は、nの量のxを含むリスト、つまり長さnのリストを作成します。各要素はxです。 _*arg_は、関数呼び出しの引数にシーケンスをアンパックします。したがって、同じイテレータを Zip() に3回渡し、毎回イテレータからアイテムを取得します。

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

他の素晴らしい回答とコメントは、 argument unpackingZip() .

Ignacio および jukatzel のように、Zip()に同じイテレータへの3つの参照を渡し、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、Noneの初期引数でmap()で同じ結果を得ることができます:

_>>> 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 /

42
bernie

すべての回答で見落とされていることの1つは(おそらくイテレータに精通している人には明らかなことですが)、他の人にはそれほど明白ではないことです。

同じイテレータがあるため、それが消費され、残りの要素が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などが使用されます。非常に微妙なことですが、かなり賢い!!!

28
gabhijit

iter(s)はsの反復子を返します。

[iter(s)]*nは、sに対してn回同じイテレータのリストを作成します。

したがって、Zip(*[iter(s)]*n)を実行すると、リストの3つのイテレータすべてから順番にアイテムが抽出されます。すべての反復子は同じオブジェクトであるため、リストをnのチャンクにグループ化するだけです。

8
sttwister

この方法でZipを使用するためのアドバイスの一言。リストの長さが均等に割り切れない場合、リストを切り捨てます。この問題を回避するには、fill値を受け入れることができる場合は 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
5
jmagnusson

おそらく、pythonインタープリターまたはipythonで_n = 2_で何が起こっているかを確認する方が簡単です:

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

したがって、同じイテレータオブジェクトを指す2つのイテレータのリストがあります。オブジェクトのiterはイテレータオブジェクトを返し、このシナリオでは、_*2_ python構文シュガー。イテレータも実行されるため、イテレータは2回同じです。 1回だけ。

さらに、 Zip は任意の数の反復可能要素( sequences are iterables )を取り、それぞれのi番目の要素からTupleを作成します入力シーケンス。今回のケースでは両方のイテレータが同一で​​あるため、Zipは出力の2要素タプルごとに同じイテレータを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.
_

npacking(_*_)演算子 は、イテレータが枯渇するまで実行します。この場合、2要素のタプルを作成するための十分な入力がなくなるまでです。

これはnの任意の値に拡張でき、Zip(*[iter(s)]*n)は説明どおりに機能します。

0
akhan