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)
ますか?より冗長なコードで記述された場合、どのように見えますか?
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)
ますか?より冗長なコードで記述された場合、どのように見えますか?
回答:
iter()
シーケンスのイテレータです。各要素がであるの数量を[x] * n
含むリスト、つまり長さのリストを生成します。関数呼び出しのシーケンスを引数にアンパックします。したがって、同じイテレータを3回に渡していて、毎回イテレータからアイテムをプルします。n
x
n
x
*arg
zip()
x = iter([1,2,3,4,5,6,7,8,9])
print zip(x, x, x)
yield
s(= return
s)するとき、このアイテムは「消費された」と想像できます。したがって、次にイテレータが呼び出されると、次の「未使用」アイテムが生成されます。
その他のすばらしい回答とコメントは、引数の解凍とzip()の役割をよく説明しています。
以下のようイグナシオとujukatzel言う、あなたはに渡す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、次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/
(おそらくイテレータに詳しい人には明白ですが)すべての回答で見落とされているものの、他の人にはそれほど明白ではないものがあると思います-
同じイテレーターがあるため、消費され、残りの要素はzipによって使用されます。したがって、単にイテラーではなくリストを使用した場合などです。
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が続きます。非常に微妙なことですが、かなり賢いです!!!
iter(s)
sの反復子を返します。
[iter(s)]*n
sの同じ反復子のn倍のリストを作成します。
そのため、を実行するzip(*[iter(s)]*n)
と、リストから3つすべてのイテレータからアイテムが順番に抽出されます。すべてのイテレータは同じオブジェクトなので、リストをのチャンクにグループ化するだけですn
。
この方法でzipを使用するための1つのアドバイス。リストの長さが均等に割り切れない場合は、リストが切り捨てられます。これを回避するには、フィル値を受け入れることができる場合は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
itertools
レシピに記載されています: docs.python.org/2/library/itertools.html#recipes grouper
。ホイールを再発明する必要はありません
Pythonインタプリタにまたは何が起こっているかを確認するために、おそらく簡単ですipython
しn = 2
。
In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]
したがって、同じイテレータオブジェクトを指している2つのイテレータのリストがあります。ことを覚えておいてくださいiter
オブジェクトのイテレータオブジェクトを返すと、このシナリオでは、それは二回に起因する同じイテレータである*2
パイソン糖衣構文。イテレータも1回だけ実行されます。
さらに、zip
任意の数の反復可能オブジェクト(シーケンスは反復可能)を取り、各入力シーケンスのi番目の要素からタプルを作成します。今回のケースでは両方のイテレーターが同一であるため、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.
アンパック(*
)演算子 2要素のタプルを作成するのに十分な入力が存在しなくなるまで、この場合にあるイテレータが枯渇に実行することを保証します。
これは、任意の値に拡張できます n
とzip(*[iter(s)]*n)
説明したように動作します。
*
は、オブジェクトを複製するのに便利です。スカラーで、次にリストで試してください。print(*zip(*[iter("ABCDEFG")]*2))
vs も試してくださいprint(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")]))
。次に、2つを小さなステップに分解して、2つのステートメントの実際のイテレータオブジェクトが何であるかを確認します。