为什么`zip`似乎消耗了`groupby`迭代?

时间:2016-12-27 20:02:50

标签: python python-3.x itertools

因此,使用itertools.groupby()拆分列表非常简单。

>>> 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]

按预期工作。但是使用zip多次迭代迭代器的常见python习惯用法一次两步,似乎会破坏事物。

>>> 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 []

添加print(y)会显示预期的嵌套可迭代<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]

2 个答案:

答案 0 :(得分:6)

groupby文档警告您

  

返回的组本身就是一个迭代器,它与groupby()共享底层的iterable。由于源是共享的,因此当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)

答案 1 :(得分:2)

因为只要您到达itertools.groupby中的下一个项目,就会丢弃之前遇到的所有_grouper - 生成器。

他们将会看到最新的项目:

>>> 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()共享底层的iterable。由于源是共享的,因此当groupby()对象处于高级时,前一个组将不再可见。因此,如果稍后需要该数据,则应将其存储为列表

因此,通过使用(x, y), _ in zip(iterable, iterable),你实际上将迭代器提高了2(即使最新结果被转储到_中),第一个(你的x, y)也不再可用了!