Python字典按键前缀分组及代码优化问题咨询
解决方案与问题解答:字典分组、setdefault用法及列表赋值陷阱
嘿,作为Python新手遇到这些问题太正常了,我来一步步帮你拆解解决:
一、最优字典分组方案(用collections.defaultdict)
这应该是最符合你需求的高效方案,defaultdict就是专门用来处理这种需要自动初始化容器的场景的,代码写起来也清爽:
from collections import defaultdict a = {'a1':'obj_1','b1':'obj_2','c1':'obj_3','a2':'obj_4','b2':'obj_5','c2':'obj_6'} result = defaultdict(dict) # 告诉它,每个新键对应的值是个空字典 for key, value in a.items(): # 取键的第一个字符,拼接成你要的分组名(比如'a'→'aonly') group_key = f"{key[0]}only" # 直接往对应的分组字典里加键值对就行,defaultdict会自动创建空字典 result[group_key][key] = value # 如果最后需要把defaultdict转成普通字典(可选,不转也能用) result = dict(result) print(result)
运行后就能得到你想要的结果:
{'aonly': {'a1': 'obj_1', 'a2': 'obj_4'}, 'bonly': {'b1': 'obj_2', 'b2': 'obj_5'}, 'conly': {'c1': 'obj_3', 'c2': 'obj_6'}}
这个方法的时间复杂度是O(n),只需要遍历一次原字典,效率拉满。
二、你的setdefault方法为什么没成功?
大概率是你之前的写法有问题,setdefault其实完全可以实现这个需求,正确的用法应该是这样:
a = {'a1':'obj_1','b1':'obj_2','c1':'obj_3','a2':'obj_4','b2':'obj_5','c2':'obj_6'} result = {} for key, value in a.items(): group_key = f"{key[0]}only" # 核心:setdefault会返回对应键的值,如果键不存在就先设置成空字典再返回 result.setdefault(group_key, {})[key] = value print(result)
你可能之前错误地把setdefault的返回值浪费了,比如单独写result.setdefault(group_key, {})然后再去赋值result[group_key][key] = value,其实链式调用一步就搞定了,这样写和defaultdict效率差不多,只是代码稍微啰嗦一点。
三、l = m = n = []为什么会出问题?
这是Python里非常经典的可变对象赋值陷阱!列表是可变对象,当你用这种单行赋值时,l、m、n三个变量其实都指向同一个内存地址里的空列表,它们并不是三个独立的列表。
比如你试试这段代码:
l = m = n = [] l.append(1) print(m) # 输出[1] print(n) # 输出[1]
是不是很意外?因为它们本质上是同一个东西。正确创建三个独立空列表的写法应该是:
l = [] m = [] n = []
或者用更简洁的列表推导式:
l, m, n = [[] for _ in range(3)]
这样每个变量都是独立的列表对象,就不会互相影响了。
四、为什么列表转字典的方法效率低?
你之前用列表存储再转字典的思路,大概是先把每个分组的键值对存成列表,最后再转成字典,比如:
# 大概是类似这样的低效写法 a_groups = {'aonly': [], 'bonly': [], 'conly': []} for key, value in a.items(): if key.startswith('a'): a_groups['aonly'].append((key, value)) elif key.startswith('b'): a_groups['bonly'].append((key, value)) elif key.startswith('c'): a_groups['conly'].append((key, value)) result = {k: dict(v) for k, v in a_groups.items()}
这种方法多了一步“列表转字典”的操作,而且如果分组变多,判断条件也会越来越长。而用defaultdict或setdefault的方法,是在遍历原字典的过程中直接构建目标字典,一步到位,内存占用更少,速度也更快。
内容的提问来源于stack exchange,提问作者Swam
相关产品推荐
相关产品推荐

