结合词典的两个词典(Python)

问题描述:

有没有简单的方法来结合Python中的字典的两个字典?这是我需要:结合词典的两个词典(Python)

dict1 = {'A' : {'B' : 'C'}} 
dict2 = {'A' : {'D' : 'E'}} 

result = dict_union(dict1, dict2) 
# => result = {'A' : {'B' : 'C', 'D' : 'E'}} 

我创建了一个强力功能做的,但我一直在寻找一个更紧凑的解决方案:

def dict_union(train, wagon): 
    for key, val in wagon.iteritems(): 
     if not isinstance(val, dict): 
      train[key] = val 
     else: 
      subdict = train.setdefault(key, {}) 
      dict_union(subdict, val) 
+5

这不是一个'dict'结合。 – 2011-06-06 18:12:59

+4

我不清楚你在结构不匹配时想要发生什么。例如,如果dict3 = {'A':'F'},那么在这里使用你的版本,dict_union(dict3,dict2)会抛出一个TypeError。这是期望的行为? – Cosmologicon 2011-06-06 18:25:21

+0

相关(但更简单):http://*.com/questions/1031199/adding-dictionaries-in-python – Gilles 2012-01-17 13:29:05

你可以继承dict,敷原dict.update()方法与一个版本,这将调用update()在subdicts而不是直接覆盖subdicts。尽管如此,这最终可能会比现有的解决方案花费更多的精力。

+0

是的,但你需要确保正在更新的字典中的任何字典也是你的子类。 – Cosmologicon 2011-06-06 18:14:42

必须是递归的,因为字典可以嵌套。这是我第一次接触它,你可能想要定义你的行为,当字典嵌套在不同的深度。

def join(A, B): 
    if not isinstance(A, dict) or not isinstance(B, dict): 
     return A or B 
    return dict([(a, join(A.get(a), B.get(a))) for a in set(A.keys()) | set(B.keys())]) 

def main(): 
    A = {'A': {'B': 'C'}, 'D': {'X': 'Y'}} 
    B = {'A': {'D': 'E'}} 
    print join(A, B) 
+0

从参数{'A':{'B':'C'}}和{'A':'F'}的OP函数返回不同的结果。不过,我不确定OP是否已经考虑过这个例子。 – Cosmologicon 2011-06-06 18:43:44

+1

是啊,你说得对,这就是我说的关于当字迹深度不同时的行为。你必须定义你自己的。我只是返回第一个非None或A或B的。你可以做'B或A',这是他的代码所做的,或者其他任何冲突解决方案。 – 2011-06-06 18:53:50

该解决方案非常紧凑。它的丑陋,但你问一些相当复杂的行为:

dict_union = lambda d1,d2: dict((x,(dict_union(d1.get(x,{}),d2[x]) if 
    isinstance(d2.get(x),dict) else d2.get(x,d1.get(x)))) for x in 
    set(d1.keys()+d2.keys())) 

至于我没有enaugh信息,但无论如何请在下面找到我的示例代码:

dict1 = {'A' : {'B' : 'C'}} 
dict2 = {'A' : {'D' : 'E'}, 'B':{'C':'D'}} 
output = {} 
for key in (set(dict1) | set(dict2): 
    output[key] = {} 
    (key in dict1 and output[key].update(dict1.get(key))) 
    (key in dict2 and output[key].update(dict2.get(key))) 

这里是一个类, RUDict(用于递归更新字典),实现您正在寻找的行为:

class RUDict(dict): 

    def __init__(self, *args, **kw): 
     super(RUDict,self).__init__(*args, **kw) 

    def update(self, E=None, **F): 
     if E is not None: 
      if 'keys' in dir(E) and callable(getattr(E, 'keys')): 
       for k in E: 
        if k in self: # existing ...must recurse into both sides 
         self.r_update(k, E) 
        else: # doesn't currently exist, just update 
         self[k] = E[k] 
      else: 
       for (k, v) in E: 
        self.r_update(k, {k:v}) 

     for k in F: 
      self.r_update(k, {k:F[k]}) 

    def r_update(self, key, other_dict): 
     if isinstance(self[key], dict) and isinstance(other_dict[key], dict): 
      od = RUDict(self[key]) 
      nd = other_dict[key] 
      od.update(nd) 
      self[key] = od 
     else: 
      self[key] = other_dict[key] 


def test(): 
    dict1 = {'A' : {'B' : 'C'}} 
    dict2 = {'A' : {'D' : 'E'}} 

    dx = RUDict(dict1) 
    dx.update(dict2) 
    print(dx) 


if __name__ == '__main__': 
    test() 


>>> import RUDict 
>>> RUDict.test() 
{'A': {'B': 'C', 'D': 'E'}} 
>>>