Python:基于对象列表的类型统计生成新的对象列表
问题分析与解决方案
哦,这个问题我之前踩过两次坑!你的代码有两个关键问题导致B类型统计始终为0:
1. itertools.groupby的分组依赖排序
groupby只会对连续的相同键进行分组,如果你的原始列表没有按Name排序,它会把不连续的同Name元素拆成多个独立分组。比如你的result列表里,Foo和Bar交替出现,groupby会生成5个分组(Foo→Bar→Foo→Bar→Foo),而不是按Foo和Bar各一组,这会直接导致统计结果混乱。
2. 迭代器只能被遍历一次
groupby返回的value是一个迭代器,而不是列表。你第一次用list(value)统计A类型时,已经把迭代器里的所有元素取完了,第二次再调用list(value)就会得到空列表,自然B类型的统计结果为0。
修正后的代码
先对原始列表按Name排序,然后遍历一次分组内的元素同时统计A、B类型的数量,避免重复消耗迭代器:
from itertools import groupby result = [ {"Name": "Foo", "Type": "A", "RandomColumn1": "1"}, {"Name": "Bar", "Type": "B", "RandomColumn2": "2"}, {"Name": "Foo", "Type": "A", "RandomColumn3": "3"}, {"Name": "Bar", "Type": "A", "RandomColumn4": "4"}, {"Name": "Foo", "Type": "B", "RandomColumn5": "5"} ] # 第一步:按Name排序,确保同Name的元素连续 sorted_result = sorted(result, key=lambda x: x["Name"]) group_requests = [] for name, items in groupby(sorted_result, key=lambda x: x["Name"]): count_a = 0 count_b = 0 # 遍历一次分组内的所有元素,同时统计A和B的数量 for item in items: if item["Type"] == "A": count_a += 1 elif item["Type"] == "B": count_b += 1 group_requests.append({ "Name": name, "A": count_a, "B": count_b }) print(group_requests)
运行这段代码就能得到你期望的输出:
[{"Name": "Foo", "A": 2, "B": 1}, {"Name": "Bar", "A": 1, "B": 1}]
额外优化(可选)
如果你的类型不止A和B,或者想让统计逻辑更灵活,可以用collections.defaultdict来统计,扩展性更强:
from itertools import groupby from collections import defaultdict sorted_result = sorted(result, key=lambda x: x["Name"]) group_requests = [] for name, items in groupby(sorted_result, key=lambda x: x["Name"]): type_counts = defaultdict(int) for item in items: type_counts[item["Type"]] += 1 # 构造结果字典,确保A和B字段存在(即使数量为0) group_item = {"Name": name, "A": 0, "B": 0} group_item.update(type_counts) group_requests.append(group_item)
这个版本即使后续新增其他类型,也能自动统计,同时保证A、B字段始终存在。
内容的提问来源于stack exchange,提问作者Mark Hayward
相关产品推荐
相关产品推荐

