使用itertools.groupby分组Python类对象列表后如何正确输出结果?
问题分析与解决方案
核心问题
你遇到的不是itertools.groupby的问题,而是Python字典的键必须唯一——你预期输出里同一个'Dog'键出现两次是不符合字典规则的,后面的赋值会直接覆盖前面的,这才是第一个Dog实例看似“缺失”的原因。
你的groupby逻辑其实是正确的:排序后的列表里两个Dog会被分到同一组,但后续循环时,每次执行report["meta"]["animals"][animal.name] = ...,都会用当前Animal的信息覆盖掉同name键的旧值,最终每个name只会保留最后一个Animal的数据。
解决方案
要保留所有同name的动物信息,需要把字典中每个name对应的value改成列表,用来存储该分组下的所有Animal数据。
修改后的代码
from collections import OrderedDict, defaultdict from itertools import groupby import json # 补充你代码中遗漏的json模块导入 class Animal: def __init__( self, name, age, description, width, height ): self.data = dict( name=name, age=age, description=description, width=width, height=height ) for k, v in self.data.items(): setattr(self, k, v) def json(self): return json.dumps(self.data) animals = [Animal('Dog', '3', 'nice dog', 12, 13), Animal('Cat', '2', 'kitty', 12, 23), Animal('Dog', '5', 'woof', 12, 13)] sorted_animals = sorted(animals, key=lambda x: x.name) # 按name分组,直接生成键为name、值为对应动物列表的字典 grouped_animals = {key: list(result) for key, result in groupby(sorted_animals, key=lambda x: x.name)} report = {"data": OrderedDict(), "meta": {"animals": defaultdict(list)}} for name, group in grouped_animals.items(): for animal in group: report["meta"]["animals"][name].append((animal.name, animal.age, animal.width)) # 可选:将defaultdict转换为普通字典 report["meta"]["animals"] = dict(report["meta"]["animals"]) print(report)
输出结果
{ 'data': OrderedDict(), 'meta': { 'animals': { 'Cat': [('Cat', '2', 12)], 'Dog': [('Dog', '3', 12), ('Dog', '5', 12)] } } }
补充说明
- 修复了原代码中遗漏的
import json(Animal.json()方法依赖该模块) - 用
defaultdict(list)自动为每个name初始化空列表,无需手动判断键是否存在 - 若你执意要实现类似“重复键”的结构(字典本身不支持),可以改用列表存储元组的形式,比如
[('Cat', ('Cat', '2', 12)), ('Dog', ('Dog', '3', 12)), ('Dog', ('Dog', '5', 12))],但这种结构的实用性远不如字典套列表。
内容的提问来源于stack exchange,提问作者mazix
相关产品推荐
相关产品推荐

