考虑一下......
from itertools import groupby
from operator import itemgetter
data = [{'pid': 1, 'items': 1}, {'pid': 2, 'items': 5}, {'pid': 1, 'items': 3}]
data = sorted(data, key=itemgetter('pid'))
for pid, rows in groupby(data, lambda x: x['pid']):
print(pid, sum(r['items'] for r in rows))
for key in ['items']:
print(pid, sum(r[key] for r in rows))
第一个print()
调用打印正确的#,4表示pid
1,5表示2.第二个print()
调用,在通过键列表的循环中,为两个打印0 。发生了什么事?
答案 0 :(得分:4)
从rows
获得的groupby
对象是一种只能被使用一次的生成器。当你为第一个print语句迭代它时,你会使用这些值,因此当你下次尝试迭代时,rows
是一个空的生成器 - 你已经访问并用完了你的访问其迭代功能。
如果您希望项目在多次迭代过程中持久,您可以使用row_list = list(rows)
然后使用row_list
。
为了更清楚,我建议将您的代码放入Python REPL并检查该循环中的type(rows)
,并查看该对象提供的API。
答案 1 :(得分:3)
你遇到了一个非常常见的生成器问题 - 它们只能迭代一次。 itertools
作为规则返回生成器。
返回的组本身就是一个迭代器,它与
groupby()
共享底层的iterable。由于源是共享的,因此当groupby()
对象前进时,前一个组将不再可见。
只需移除您的print()
个来电,然后观看即可。如果您需要多次访问返回的数据,列表是保存结果的潜在结构。
答案 2 :(得分:3)
固定代码:
from itertools import groupby
from operator import itemgetter
data = [{'pid': 1, 'items': 1}, {'pid': 2, 'items': 5}, {'pid': 1, 'items': 3}]
data = sorted(data, key=itemgetter('pid'))
for pid, rows_gen in groupby(data, lambda x: x['pid']):
rows=list(rows_gen) # save the group to access more than once
print(pid, sum(r['items'] for r in rows))
for key in ['items']:
print(pid, sum(r[key] for r in rows))