假设我有两个字典:
dic1 = { "first":1, "second":4, "third":8}
dic2 = { "first":9, "second":5, "fourth":3}
有没有一种简单的方法可以获得以下类似的内容?
dic3 = { "first":[1,9], "second":[4,5], "third":[8], "fourth":[3]}
我使用列表来存储值,但元组也可以。
假设我有两个字典:
dic1 = { "first":1, "second":4, "third":8}
dic2 = { "first":9, "second":5, "fourth":3}
有没有一种简单的方法可以获得以下类似的内容?
dic3 = { "first":[1,9], "second":[4,5], "third":[8], "fourth":[3]}
我使用列表来存储值,但元组也可以。
defaultdict
来保存列表,并将值附加到它们上。这种方法可以轻松地扩展到任意数量的字典。from collections import defaultdict
dd = defaultdict(list)
dics = [dic1, dic2]
for dic in dics:
for key, val in dic.iteritems(): # .items() in Python 3.
dd[key].append(val)
>>> dict(dd)
{'first': [1, 9], 'fourth': [3], 'second': [4, 5], 'third': [8]}
所有单值键仍然保存在列表中,这可能是最好的方法。不过,您可以将任何长度为1的内容更改为实际值,例如
for key, val in dd.iteritems(): # .items() in Python 3.
if len(val) == 1
dd[key] = val[0]
defaultdict
中所有的值都是 list
类型,即使在键中没有重复的值。如果期望的行为是保留单个值作为该值的类型,那么我们应该在添加之前检查键是否存在,并且只有当该键已经存在时才转换为列表。 - ctj232dic1 = {"first": 1, "second": 4, "third": 8}
dic2 = {"first": 9, "second": 5, "fourth": 3}
dic3 = dict(dic2)
for k, v in dic1.items():
dic3[k] = [dic3[k], v] if k in dic3 else v
print(dic3) # => {'first': [9, 1], 'second': [5, 4], 'fourth': 3, 'third': 8}
dic3 = {k: [v] for k, v in dic2.items()}
for k, v in dic1.items():
dic3[k] = dic3[k] + [v] if k in dic3 else [v]
print(dic3) # => {'first': [9, 1], 'second': [5, 4], 'fourth': [3], 'third': [8]}
def merge_dicts(*dicts):
"""
>>> merge_dicts({"a": 2}, {"b": 4, "a": 3}, {"a": 1})
{'a': [2, 3, 1], 'b': [4]}
"""
merged = {}
for d in dicts:
for k, v in d.items():
if k not in merged:
merged[k] = []
merged[k].append(v)
return merged
collections.defaultdict
来使代码更加简洁:from collections import defaultdict
def merge_dicts(*dicts):
"""
>>> merge_dicts({"a": 2}, {"b": 4, "a": 3}, {"a": 1})
defaultdict(<class 'list'>, {'a': [2, 3, 1], 'b': [4]})
"""
merged = defaultdict(list)
for d in dicts:
for k, v in d.items():
merged[k].append(v)
return merged
给定:
dic1 = { "first":1, "second":4, "third":8}
dic2 = { "first":9, "second":5, "fourth":3}
.setdefault
方法:dic_new={}
for k,v in list(dic1.items())+list(dic2.items()):
dic_new.setdefault(k, []).append(v)
else:
dic_new={k:v if len(v)>1 else v[0] for k,v in dic_new.items()}
>>> dic_new
{'first': [1, 9], 'second': [4, 5], 'third': 8, 'fourth': 3}
这将产生所需的输出。我认为将单个元素列表展平到不同的对象类型是一种不必要的复杂性。
经过编辑,这将产生所需的结果:
dic_new={}
for k,v in list(dic1.items())+list(dic2.items()):
dic_new.setdefault(k, []).append(v)
>>> dic_new
{'first': [1, 9], 'second': [4, 5], 'third': [8], 'fourth': [3]}
L = [d1, d2]
dups = set(d1.keys() & d2.keys())
d = {k: [L[0][k], L[1][k]] if k in dups else i[k] for i in L for k in i}
{'first': [1, 9], 'second': [4, 5], 'third': 8, 'fourth': 3}
def merge_values(val1, val2):
if val1 is None:
return [val2]
elif val2 is None:
return [val1]
else:
return [val1, val2]
dict3 = {
key: merge_values(dic1.get(key), dic2.get(key))
for key in set(dic1).union(dic2)
}
dic
,其键为dic1
和dic2
的键,值为一个空列表,然后迭代dic1
和dic2
将值附加到dic
中。dic1 = { "first":1, "second":4, "third":8}
dic2 = { "first":9, "second":5, "fourth":3}
dic = {key:[] for key in list(dic1.keys()) + list(dic2.keys())}
for key in dic1.keys():
dic[key].append(dic1[key])
for key in dic2.keys():
dic[key].append(dic2[key])
dic1.keys() + dic2.keys()
会导致TypeError
错误。 - dawgsum
不再适用于任意类型。
对字符串列表求和非常方便。 - Scrooge McDuckdic = {key:[] for key in {k for k in list(dic1) + list(dic2)}}
来使其更加高效,这样就可以消除重复的键。 - dawg''.join
的影响?很抱歉,我无法理解该链接与sum
的关系。文章中描述的冗余计算取决于+
的实现;因此,如果对于Python而言是这种情况,那么使用+
连接n个字符串的任何串联都是有效的join
。那么,为什么不将字符串之间的+
别名为二进制''。join
字符串的sum
,以替换低效的字符串连接器呢? - Scrooge McDuck字典列表的解决方案(改编自@dawg):
dic1 = { "first":[1], "second":[4], "third":[8]}
dic2 = { "first":[9], "second":[5], "fourth":[3]}
dic_new={}
for k,v in list(dic1.items())+list(dic2.items()):
dic_new.setdefault(k, []).extend(v)
>>> dic_new
{'first': [1, 9], 'second': [4, 5], 'third': [8], 'fourth': [3]}
from copy import deepcopy
def _add_value_to_list(value, lis):
if value:
if isinstance(value, list):
lis.extend(value)
else:
lis.append(value)
else:
pass
def _merge_value(value_a, value_b):
merged_value = []
_add_value_to_list(value_a, merged_value)
_add_value_to_list(value_b, merged_value)
return merged_value
def _recursion_merge_dict(new_dic, dic_a, dic_b):
if not dic_a or not dic_b:
return new_dic
else:
if isinstance(new_dic, dict):
for k, v in new_dic.items():
new_dic[k] = _recursion_merge_dict(v, dic_a.get(k, {}), dic_b.get(k, {}))
return new_dic
else:
return _merge_value(dic_a, dic_b)
def merge_dicts(dic_a, dic_b):
new_dic = deepcopy(dic_a)
new_dic.update(dic_b)
return _recursion_merge_dict(new_dic, dic_a, dic_b)