在python中合并两个dicts,不允许重复

时间:2015-07-09 16:35:28

标签: python dictionary merge

此问题与类似的字典合并问题的区别在于冲突的重复项应该失败,或者返回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

有任何改进吗?

5 个答案:

答案 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