合并字典时保留重复键的值
给定n个字典,写一个函数,返回一个独特的字典,对于重复的键,值用列表的形式表示。
举个例子:
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'b': 4}
d3 = {'a': 5, 'd': 6}
结果:
>>> newdict
{'c': 3, 'd': 6, 'a': [1, 5], 'b': [2, 4]}
我目前的代码:
>>> def merge_dicts(*dicts):
... x = []
... for item in dicts:
... x.append(item)
... return x
...
>>> merge_dicts(d1, d2, d3)
[{'a': 1, 'b': 2}, {'c': 3, 'b': 4}, {'a': 5, 'd': 6}]
有什么好的方法可以生成一个新的字典,让那些重复的键对应的值变成一个列表吗?
2 个回答
Python 提供了一个简单又快速的解决方案:在 collections
模块中的 defaultdict
。下面是文档中的一些例子:
使用
list
作为default_factory
,可以很方便地把一系列的键值对分组到一个字典中,每个键对应一个列表:>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', 1), ('yellow', [1, 3])]当第一次遇到某个键时,如果这个键还不在字典里,Python 会自动用
default_factory
函数创建一个新的条目,这个函数会返回一个空列表。接着,list.append()
操作会把这个值添加到新创建的列表中。当再次遇到同样的键时,Python 会正常查找(返回该键对应的列表),然后list.append()
操作会把另一个值添加到这个列表里。
在你的情况下,大致可以这样理解:
import collections
def merge_dicts(*dicts):
res = collections.defaultdict(list)
for d in dicts:
for k, v in d.iteritems():
res[k].append(v)
return res
>>> merge_dicts(d1, d2, d3)
defaultdict(<type 'list'>, {'a': [1, 5], 'c': [3], 'b': [2, 4], 'd': [6]})
def merge_dicts(*dicts):
d = {}
for dict in dicts:
for key in dict:
try:
d[key].append(dict[key])
except KeyError:
d[key] = [dict[key]]
return d
这个返回的是:
{'a': [1, 5], 'b': [2, 4], 'c': [3], 'd': [6]}
这里和问题有一点小区别。这里所有的字典值都是列表。如果你不想让长度为1的列表也变成列表的话,可以在:
for key in d:
if len(d[key]) == 1:
d[key] = d[key][0]
在return d
语句之前加上这一行。不过,我真的很难想象在什么情况下你会想要去掉这个列表。(想象一下你有列表作为值的情况;那么去掉这些项外面的列表就会导致一些模糊的情况。)