如何按多键将Python字典分组为层级结构?
按topic和subtopic分组字典列表的解决方案
问题描述
原始数据
[{'subtopic': 'kuku', 'topic': 'lulu', 'attachments': ['ttt'], 'text': 'abc'}, {'subtopic': 'tutu', 'topic': 'lulu', 'attachments': ['pipu'], 'text': 'bubb'}, {'subtopic': 'did', 'topic': 'lulu', 'attachments': ['ktop'], 'text': 'gfg'}, {'subtopic': 'polo', 'topic': 'lulu', 'attachments': ['vuvu'], 'text': 'prolo'}, {'subtopic': 'ssd', 'topic': 'lulu', 'attachments': ['jkjk'], 'text': 'vint'}, {'subtopic': 'plp', 'topic': 'lulu', 'attachments': ['fre'], 'text': 'viw'}, {'subtopic': 'prw', 'topic': 'kll', 'attachments': [], 'text': 'kkk'}, {'subtopic': 'prw', 'topic': 'kll', 'attachments': [], 'text': 'fgfger2'}]
期望目标格式
{ "lulu": { "kuku": { 'attachments': ['ttt'], 'text': ['abc'] }, "tutu": { 'attachments': ['pipu'], 'text': ['bubb'] }, "did": { 'attachments': ['ktop'], 'text': ['gfg'] }, "polo": { 'attachments': ['vuvu'], 'text': ['prolo'] }, "ssd": { 'attachments': ['jkjk'], 'text': ['vint'] }, "plp": { 'attachments': ['fre'], 'text': ['viw'] } }, "kll": { "prw": { 'attachments': [], 'text': ['kkk', 'fgfger2'] } } }
原错误代码
import itertools import operator groups = ['topic', 'subtopic', "text", "attachments"] groups.reverse() def hierachical_data(data, groups): g = groups[-1] g_list = [] for key, items in itertools.groupby(data, operator.itemgetter(g)): g_list.append({key:list(items)}) groups = groups[0:-1] if(len(groups) != 0): for e in g_list: for k, v in e.items(): e[k] = hierachical_data(v, groups) return g_list filtered_top_facts_dicts = [{'subtopic': 'kuku',...}] # 原始数据列表 print(hierachical_data(filtered_top_facts_dicts, groups))
错误原因
- 原代码错误地将
attachments(列表类型)作为分组键,而itertools.groupby要求分组键必须是可哈希类型,列表不可哈希,因此抛出错误。 - 分组逻辑不符合目标需求:目标是先按
topic、再按subtopic分组,最后收集同组的text和attachments为列表,而非对这两个字段再次分组。
修正后的代码
from collections import defaultdict def group_by_topic_subtopic(data): # 构建嵌套默认字典,自动创建不存在的层级键 result = defaultdict(lambda: defaultdict(lambda: {'attachments': [], 'text': []})) for item in data: topic = item['topic'] subtopic = item['subtopic'] # 收集attachments(用extend合并列表)和text(用append添加单个元素) result[topic][subtopic]['attachments'].extend(item['attachments']) result[topic][subtopic]['text'].append(item['text']) # 将嵌套defaultdict转换为普通字典(可选操作,按需保留) return {k: dict(v) for k, v in result.items()} # 测试数据 filtered_top_facts_dicts = [ {'subtopic': 'kuku', 'topic': 'lulu', 'attachments': ['ttt'], 'text': 'abc'}, {'subtopic': 'tutu', 'topic': 'lulu', 'attachments': ['pipu'], 'text': 'bubb'}, {'subtopic': 'did', 'topic': 'lulu', 'attachments': ['ktop'], 'text': 'gfg'}, {'subtopic': 'polo', 'topic': 'lulu', 'attachments': ['vuvu'], 'text': 'prolo'}, {'subtopic': 'ssd', 'topic': 'lulu', 'attachments': ['jkjk'], 'text': 'vint'}, {'subtopic': 'plp', 'topic': 'lulu', 'attachments': ['fre'], 'text': 'viw'}, {'subtopic': 'prw', 'topic': 'kll', 'attachments': [], 'text': 'kkk'}, {'subtopic': 'prw', 'topic': 'kll', 'attachments': [], 'text': 'fgfger2'} ] # 执行并格式化输出 result = group_by_topic_subtopic(filtered_top_facts_dicts) import json print(json.dumps(result, indent=2))
代码说明
- 嵌套默认字典:用
defaultdict自动创建topic和subtopic层级,避免手动判断键是否存在,简化代码逻辑。 - 数据收集:遍历原始数据,将每个条目的
attachments合并到对应分组的列表中,text添加到对应分组的列表中。 - 类型转换:最后将嵌套的
defaultdict转为普通字典,保证输出格式符合常规字典结构(若不需要可省略此步骤)。
输出结果
{ "lulu": { "kuku": { "attachments": ["ttt"], "text": ["abc"] }, "tutu": { "attachments": ["pipu"], "text": ["bubb"] }, "did": { "attachments": ["ktop"], "text": ["gfg"] }, "polo": { "attachments": ["vuvu"], "text": ["prolo"] }, "ssd": { "attachments": ["jkjk"], "text": ["vint"] }, "plp": { "attachments": ["fre"], "text": ["viw"] } }, "kll": { "prw": { "attachments": [], "text": ["kkk", "fgfger2"] } } }
内容的提问来源于stack exchange,提问作者SteveS
相关产品推荐
相关产品推荐

