Python如何对嵌套字典列表按相同键名分组
二层嵌套单键字典列表按键名分组实现方案
核心问题说明
原有方案失效的核心原因有三点:
itertools.groupby默认不会自动按字典键名分组,需要手动传入提取分组键的函数,之前传入的分组逻辑是取字典指定键对应的值,和按键名分组的需求不匹配groupby仅能将连续的同组元素聚合,展平后如果同键名的字典不相邻,不提前排序的话会出现分组错误- 不需要依赖
numpy.concatenate做展平,原生Python列表操作即可完成需求,性能更好。
最优实现(字典归集法,时间复杂度O(n))
用字典做分组容器是性能最高的实现,不需要排序,一次遍历即可完成归集:
- 初始化以键名为索引、列表为值的分组容器
- 两层遍历原嵌套结构,逐个取出每个单键字典的唯一键名
- 将字典追加到容器中对应键名的列表下
- 最后取出容器的所有值即为目标结构
from collections import defaultdict # 替换为实际包含27个子列表的原结构即可 original_nested_list = [ [{"key1": "v1"}, {"key2": "v2"}, {"key3": "v3"}], [{"key1": "v4"}, {"key2": "v5"}, {"key3": "v6"}], [{"key1": "v7"}, {"key2": "v8"}, {"key3": "v9"}] ] group_container = defaultdict(list) for sub_list in original_nested_list: for single_key_dict in sub_list: # 提取单键字典的唯一键名 current_key = next(iter(single_key_dict.keys())) group_container[current_key].append(single_key_dict) # 转换为要求的父列表嵌套子列表结构 final_result = list(group_container.values())
运行后final_result的每个子列表对应唯一键名,归集了原结构中所有该键名的单键字典。以上述示例数据为例,输出结构如下:
[ [{'key1': 'v1'}, {'key1': 'v4'}, {'key1': 'v7'}], [{'key2': 'v2'}, {'key2': 'v5'}, {'key2': 'v8'}], [{'key3': 'v3'}, {'key3': 'v6'}, {'key3': 'v9'}] ]
可选实现(itertools.groupby 版本)
如果需要沿用itertools.groupby的实现逻辑,需要先展平列表、再按字典键名排序后再分组。该方法时间复杂度为O(nlogn),数据量大时性能弱于字典归集法:
import itertools # 展平嵌套列表 flatten_list = [] for sub_list in original_nested_list: flatten_list.extend(sub_list) # 必须先按分组键排序,保证同键名字典相邻 flatten_list.sort(key=lambda d: next(iter(d.keys()))) # 按单键字典的键名分组 final_result = [list(group) for _, group in itertools.groupby( flatten_list, key=lambda d: next(iter(d.keys())) )]
注意:Python 3.7之前的版本中普通字典是无序的,如果需要保留原键名的出现顺序,使用
collections.defaultdict即可保证顺序和原结构中键第一次出现的顺序一致。
内容的提问来源于stack exchange,提问作者Kale
相关产品推荐
相关产品推荐

