此问题与类似的字典合并问题的区别在于冲突的重复项应该失败,或者返回False 。其他解决方案使用优先规则来决定如何管理一个键可能映射到两个不同的变量。
如何在python中有效地合并两个dicts。例如,请考虑:
d1 = {'x': 'a', 'y': 'b', 'z': 'c'}
d2 = {'z': 'c', 'w': 'r'}
d3 = {'z': 'd', 'w': 'r'}
因此,合并字典1和2的结果将是
{'x': 'a', 'y': 'b', 'z': 'c', 'w': 'r'}
但是1和3或2和3的合并应该失败,因为z
存在冲突。
我的解决方案是:
def merge_dicts(d1,d2):
k1=d1.keys()
k2=d2.keys()
unified_dict=dict()
for k in k1:
# look up in second dictionary
if k in k2:
pt=d2[k] #pt stands for 'plain text'
# if lookup is a contradiction, return empty dictionary
# don't even bother with partial results
if pt!=d1[k]:
return dict()
else:
unified_dict[k]=d1[k] # safe: key is consistent
else:
unified_dict[k]=d1[k] # safe: no key in k2
# get the rest
# already resolved intersection issues so just get set difference
for k in d2.keys():
if k not in d1.keys():
unified_dict[k]=d2[k]
return unified_dict
有任何改进吗?
答案 0 :(得分:5)
在这里使用dictionary views;他们让你将字典键视为集合:
def merge_dicts(d1, d2):
try:
# Python 2
intersection = d1.viewkeys() & d2
except AttributeError:
intersection = d1.keys() & d2
if any(d1[shared] != d2[shared] for shared in intersection):
return {} # empty result if there are conflicts
# leave the rest to C code, execute a fast merge using dict()
return dict(d1, **d2)
以上代码仅测试引用不匹配值的共享密钥;合并本身最好留给dict()
函数。
我在Python 2和Python 3上都使用了该功能;如果您只需要支持其中一个,请移除try..except
并将intersection
替换为相关表达式。在Python 3中,dict.keys()
方法默认返回字典视图。
你可以想象这是一个单行; Python 3版本:
def merge_dicts(d1, d2):
return {} if any(d1[k] != d2[k] for k in d1.keys() & d2) else dict(d1, **d2)
演示:
>>> d1 = {'x': 'a', 'y': 'b', 'z': 'c'}
>>> d2 = {'z': 'c', 'w': 'r'}
>>> d3 = {'z': 'd', 'w': 'r'}
>>> merge_dicts(d1, d2)
{'y': 'b', 'x': 'a', 'z': 'c', 'w': 'r'}
>>> merge_dicts(d1, d3)
{}
>>> merge_dicts(d2, d3)
{}
答案 1 :(得分:2)
d1 = {'x': 'a', 'y': 'b', 'z': 'c'}
d2 = {'z': 'c', 'w': 'r'}
d3 = {'z': 'd', 'w': 'r'}
def dict_merge(d1, d2):
"""docstring for merge"""
# doesn't work with python 3.x. Use keys(), items() instead
if len(d1.viewkeys() & d2) != len(d1.viewitems() & d2.viewitems()):
return {}
else:
result = dict(d1, **d2)
return result
if __name__ == '__main__':
print dict_merge(d1, d2)
答案 2 :(得分:1)
略有不同的方法(预检):
d1={'x':'a','y':'b','z':'c'}
d2={'z':'c','w':'r'}
d3={'z':'d','w':'r'}
def merge(d1, d2):
for (k1,v1) in d1.items():
if k1 in d2 and v1 != d2[k1]:
raise ValueError
ret = d1.copy()
ret.update(d2)
return ret
print(merge(d1,d2))
print(merge(d1,d3))
答案 3 :(得分:1)
为什么不使用set?
#!/usr/bin/python
d1={'x':'a','y':'b','z':'c'}
d2={'w':'r'}
d3={'z':'d','w':'r'}
d4={'x':'a','y':'b','z':'c'}
def merge_dicts(d1, d2):
dicts = d1.items() + d2.items()
if len(dicts) != len(set(dicts)):
raise ValueError
else:
return dict(set(dicts))
print merge_dicts(d1, d2)
print merge_dicts(d1, d3)
try:
print merge_dicts(d1, d4)
except:
print "Failed"
$ python foo.py
{'y': 'b', 'x': 'a', 'z': 'c', 'w': 'r'}
{'y': 'b', 'x': 'a', 'z': 'd', 'w': 'r'}
Failed
编辑:
实际上,这不适用于不可用的值,这个会:
#!/usr/bin/python
# coding: utf-8
#!/usr/bin/python
d1={'x':'a','y':'b','z':'c'}
d2={'w':'r'}
d3={'z':'d','w':'r'}
d4={'x':'a','y':'b','z':'c'}
def merge_dicts(d1, d2):
merged= d1.copy()
for k, v in d2.iteritems():
if k in merged:
raise ValueError
else:
merged[k] = v
return merged
for one, two in [(d1, d2), (d1, d3), (d1, d4)]:
try:
print merge_dicts(one, two)
except:
print "Merge Failed for %s with %s" %(one, two)
答案 4 :(得分:1)
这样做你想要的:
def merge_dicts(d1, d2):
# Join dicts and get rid of non-conflicting dups
elems = set(d1.items()) | set(d2.items())
# Construct join dict
res = {}
for k, v in elems:
if k in res.keys():
return dict() # conflicting dup found
res[k] = v;
return res