任何人都可以解释为什么迭代迭代器X生成的列表与迭代迭代器X相比产生不同的结果?
换句话说,[x表示列表中的x(IteratorObject)]!= [x表示IteratorObject中的x]
>>> randoms = [random.randrange(10) for i in range(100)]
>>> [ (x[0],list(x[1])) for x in itertools.groupby(sorted(randoms))]
[(0, [0, 0, 0, 0, 0, 0, 0, 0]), (1, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]), (2, [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]), (3, [3, 3, 3, 3, 3, 3]), (4, [4, 4, 4, 4, 4, 4, 4, 4, 4, 4]), (5, [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]), (6, [6, 6, 6, 6, 6, 6, 6, 6, 6]), (7, [7, 7, 7, 7, 7]), (8, [8, 8, 8, 8, 8, 8, 8]), (9, [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9])]
>>> [ (x[0],list(x[1])) for x in list(itertools.groupby(sorted(randoms)))]
[(0, []), (1, []), (2, []), (3, []), (4, []), (5, []), (6, []), (7, []), (8, []), (9, [9])]
>>> sys.version
'3.3.3 (default, Dec 2 2013, 01:40:21) \n[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)]'
答案 0 :(得分:3)
我认为文档中的这一点解释了问题:
“返回的组本身是一个迭代器,它与groupby()共享底层的iterable。由于源是共享的,当groupby()对象被提前时,前一个组不再可见。所以,如果该数据是稍后需要,它应该存储为列表“
在第二个示例中,当您转换为列表时,您会立即遍历所有组。但是在每个组中,您不会遍历底层元素。当你最终尝试用list(x [1])来做这件事时,为时已晚 - 你已经用尽了迭代器。
答案 1 :(得分:2)
从itertools.groupby
为每个组产生的迭代器不是独立于顶级迭代。在进入下一个组之前,您需要使用它们中的每一个,否则迭代器将变为无效(它将不再产生任何结果)。
the docs中引用了此行为:
返回的组本身就是一个迭代器,它与
groupby()
共享底层的iterable。由于源是共享的,因此当groupby()
对象前进时,前一个组不再可见。因此,如果以后需要该数据,则应将其存储为列表
你的两个列表理解显示了这一点。在第一个中,您在list
上调用x[1]
,这是迭代器。在第二个版本中,所有迭代器首先在围绕list
调用的groupby
调用中生成,并且只有当您遍历该列表时才会消耗内部迭代器。请注意,最后一个组([9]
)上的迭代器确实有效!
这是一个更简单的例子:
groupby_iter = itertools.groupby([1,1,2,2])
first_val, first_group = next(groupby_iter)
# right now, we can iterate on `first_group`:
print(next(first_group)) # prints 1
# but if we advance groupby_iter to the next group...
second_val, second_group = next(groupby_iter)
# first_group is now invalid (it won't yield the second 1)
print(next(first_group)) # raises StopIteration