字典推导时检查键是否存在并实现同键值求和的最优方法
嘿,这个问题我太熟了!先给你划个重点:字典推导其实不是处理这种「按键累积求和」需求的最优选择——因为推导式是一次性生成键值对的声明式语法,没法在推导过程中修改已经生成的键对应的值。下面给你几个实用的方案,按可读性和效率排序:
最优方案1:普通for循环(最直观,无额外依赖)
这是最直接的写法,新手也能一眼看懂,而且性能拉满:
items = [('a', 1), ('b', 2), ('a', 3), ('c', 4), ('b', 5)] result = {} for key, value in items: if key in result: result[key] += value else: result[key] = value # 最终结果: {'a':4, 'b':7, 'c':4}
这里完美实现了你想要的「检查键是否存在+else分支」逻辑,比硬套字典推导灵活得多,还能随时加额外的处理逻辑。
最优方案2:用collections.defaultdict(更简洁)
如果不想写if-else判断,可以用Python标准库的defaultdict,它会自动给不存在的键设置默认值(这里我们用int,默认值就是0):
from collections import defaultdict items = [('a', 1), ('b', 2), ('a', 3), ('c', 4), ('b', 5)] result = defaultdict(int) for key, value in items: result[key] += value # 要是需要转成普通字典(可选操作) result = dict(result)
这个写法更简洁,省去了手动检查键的步骤,和普通循环效率几乎一样,是日常开发里最常用的方法。
备选方案:itertools.groupby(仅适合有序数据)
如果你的原始数据已经按item[0]排序好,可以用itertools.groupby来分组求和:
from itertools import groupby from operator import itemgetter # 注意:数据必须先按key排序,否则groupby会把不连续的相同键当成不同组 items = [('a', 1), ('a', 3), ('b', 2), ('b', 5), ('c', 4)] result = { key: sum(v for _, v in group) for key, group in groupby(items, key=itemgetter(0)) }
但要注意:groupby只会把连续相同的键分到一组,如果数据没排序,会导致求和错误。而且排序会带来O(n log n)的时间开销,所以如果数据未排序,不如用前面两种O(n)时间复杂度的方法。
为什么不推荐硬套字典推导?
硬要在字典推导里实现的话,只能用一些违背设计初衷的hack(比如借助可变对象保存状态),比如:
items = [('a', 1), ('b', 2), ('a', 3), ('c', 4), ('b', 5)] result = {} {result.__setitem__(key, result.get(key, 0) + value) for key, value in items}
这种写法可读性极差,还利用了推导式的副作用操作,完全不符合Python的代码风格,绝对不推荐。
总结一下:日常开发优先选defaultdict或者普通for循环,前者简洁,后者无额外依赖;如果数据已排序,groupby可以作为备选,但记得先排序。
内容的提问来源于stack exchange,提问作者jsstuball
相关产品推荐
相关产品推荐

