10

ジェネレーターを使用してネストされたループの動作を説明していただけませんか?これが例です。

a = (x for x in range(3))
b = (x for x in range(2))
for i in a:
    for j in b:
        print (i,j)

何らかの理由で、最初の反復後に外側のループが評価されません。結果は、

(0, 0)
(0, 1)

一方、ジェネレーターがループに直接挿入されている場合、それは私が期待することを行います。

for i in (x for x in range(3)):
    for j in (x for x in range(2)):
        print (i,j)

すべての3x2ペアを提供します。

(0, 0)
(0, 1)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
4

3 に答える 3

25

これbは、外側のforループの最初の反復中にジェネレーターが使い果たされたためです。後続の反復では、実際には(のようなfor x in ())空の内部ループが存在するため、内部にあるものは実行されません。これは、どういうわけか、失敗するのは外側のループであるという誤った印象を与えます。

2番目の例は、外部ループごとに内部ジェネレーターが新たに作成されるため、機能します。最初の例を修正するには、同じことを行う必要があります。

a = (x for x in range(3))
for i in a:
    b = (x for x in range(2))
    for j in b:
        print (i,j)
于 2012-07-19T21:26:50.263 に答える
8

@lazyrはこれに見事に答えましたが、ネストされたジェネレーターを使用する場合は知っておく価値があることを参考に指摘しておきitertools.productます...

for i, j in itertools.product(range(3), range(2)):
    print (i, j)

または(valがたくさんある場合):

for vals in itertools.product(range(45), range(12), range(3)):
    print (sum(vals))

(IMHO)読み取り可能で、過度のインデントを回避します。

于 2012-07-19T21:37:53.560 に答える
0

itertools.productは、この例に最適です。ただし、反復中にさらに多くのオプションが必要になる場合があります。productメソッドを使用せずに、例で製品を取得する1つの方法を次に示します。

a = (range(2) for x in range(3))
for i in a:
    for j in i:
        print (i,j)

また、pytoolz機能ヘルパーライブラリのitertoolz.concatを使用して、このようなケースを合理化/フラット化しますconcatはitertools.chainと同じですが、代わりに、解明されるイテレータを生成する単一の引数を取ります。

from pytoolz import itertoolz
a = (((x,y) for y in range(2)) for x in range(3))
for i,j in itertoolz.concat(a):
    print (i,j)

したがって、上記は製品メソッドよりも読みにくいように見えますが、各ループレベルでよりきめ細かい変換/フィルタリングが可能です。そしてもちろん、最後の反復ロジックではネストされたforループはありません。

また、pytoolzを使用する場合は、おそらくcytoolzを使用する必要があります。これは、Cにコンパイルされた同じライブラリです。

于 2015-06-05T14:56:00.990 に答える