2016-12-27 10 views
3

itertools.groupby()を使ってリストを分割するのはかなり簡単です。なぜ `zip`は` groupby` iterableを消費するようですか?

>>> import itertools as it 
>>> iterable = it.groupby([1, 2, 3, 4, 5, 2, 3, 4, 2], lambda p: p==2) 
>>> for x, y in iterable: 
...  print(x, list(y)) 
...  next(iterable) 
False [1] 
False [3, 4, 5] 
False [3, 4] 

期待どおりに動作します。しかし、一般的なPythonのイディオムzipを使ってイテレータを複数回実行すると、一度に2つずつステップを踏みだすように見えます。 print(y)を追加

>>> iterable = it.groupby([1, 2, 3, 4, 5, 2, 3, 4, 2], lambda p: p==2) 
>>> for (x, y), _ in zip(iterable, iterable): 
...  print(x, list(y)) 
False [] 
False [] 
False [] 

は期待ネストされた反復可能な<itertools._grouper object at 0xXXXXXXXX>を示しているが、私は明らかにgrouperオブジェクトが空である理由として、何かが欠けています。誰か光を当てることはできますか?

私は不均一なリストを持っているとitertools.zip_longestを使用している場合、私も奇妙な結果を得る:

>>> iterable = it.groupby([1, 2, 3, 4, 5, 2, 3, 4], lambda p: p==2) 
>>> for (x, y), _ in it.zip_longest(iterable, iterable, fillvalue=None): 
...  print(x, list(y)) 
False [] 
False [] 
False [4] 

更新:簡単な修正はitertools.islice()を使用することです:

>>> iterable = it.groupby([1, 2, 3, 4, 5, 2, 3, 4, 2], lambda p: p==2) 
>>> for x, y in it.islice(iterable, None, None, 2): 
...  print(x, list(y)) 
False [1] 
False [3, 4, 5] 
False [3, 4] 
+1

[itertools.groupbyの予期しない動作](http://stackoverflow.com/questions/35991852/unexpected-behavior-of-itertools-groupby) – vaultah

答えて

5

groupbyドキュメントは警告を表示しますその

返されるグループ自体は、基本となるiterableをgroupby()と共有するイテレータです。ソースが共有されているため、groupby()オブジェクトがアドバンスされている場合、は以前のグループは表示されなくなりました

あなたzip((key, group), (key, group))ペアを生成するとき、それは最初のグループ使用できなくレンダリング、最初のグループ過去groupbyイテレータを進めます。あなたは進む前にグループを実体化する必要があります。

iterable = ((key, list(group)) for (key, group) in it.groupby([1, 2, 3, 4, 5, 2, 3, 4, 2], lambda p: p==2)) 
for (x, y), _ in zip(iterable, iterable): 
    print(x, y) 
+0

ありがとうございました。最後の反復でグループ化が進んでいないとすれば、 'zip_longest'の最終結果は' [4] 'であり、' [3、4] 'ではありません。 – AChampion

+0

@AChampion:しかし、 'groupby'は根本的な反復子を進化させて最終的なグループがないことを知る必要があるので、*これは進歩しています。 (なぜなら '[] 'の代わりに' [4]'の理由は、提供されたリンクvaultahで述べられている実装の詳細のためです)。 – user2357112

2

とすぐにitertools.groupbyの次の項目に着くと、それは以前に遭遇_grouper -generatorsを破棄しているため。

最新アイテム、彼らが表示されます:

>>> iterable = it.groupby([1, 2, 3, 4, 5, 2, 3, 4, 2], lambda p: p==2) 
>>> for (x, y), (x2, y2) in zip(iterable, iterable): 
...  print(x2, list(y2)) 
True [2] 
True [2] 
True [2] 

documentationはこの動作に関する警告が含まれています

返されるグループは、それ自体GROUPBYで反復可能になる株式イテレータです() 。ソースは共有されているため、groupby()オブジェクトが拡張されると、以前のグループは表示されなくなります。したがって、後でそのデータが必要な場合は、それはリストとして保存する必要があります。

ので(x, y), _ in zip(iterable, iterable)を使用することによって、あなたが実際に2(最新の結果は_に投棄されている場合でも)と第1の1(あなたのx, y)反復子を進めたが、もはや下盛ではありません!

関連する問題