合并两个字典中的字典(Python)

合并两个字典中的字典(Python),python,dictionary,union,Python,Dictionary,Union,有没有一种简单的方法可以组合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

有没有一种简单的方法可以组合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)

您可以将
dict
子类化,并将原始
dict.update()
方法包装为一个版本,该版本将对子部分调用
update()
,而不是直接覆盖子部分。不过,这可能会花费至少与现有解决方案一样多的精力。

必须是递归的,因为字典可能嵌套。这是我对它的第一个看法,当字典嵌套在不同的深度时,您可能想定义自己的行为

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)

这个解决方案非常紧凑。这很难看,但你要求的是一些相当复杂的行为:

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()))

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

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(用于递归更新dict),它实现了您所寻找的行为:

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'}}
>>>

我的解决方案是设计来组合任意数量的字典的,如果将其限制为只组合两个字典,可能会被简化为看起来更整洁,但其背后的逻辑应该很容易在程序中使用

def dictCompressor(*args):
    output = {x:{} for mydict in args for x,_ in mydict.items()}
    for mydict in args:
        for x,y in mydict.items():
            output[x].update(y)
    return output

是的,但是你需要确保dicts中所有被更新的dicts都是你的子类的实例。我不清楚当dicts的结构不匹配时你希望发生什么。例如,如果dict3={'A':'F'},那么在这里使用您的版本,dict_union(dict3,dict2)抛出一个TypeError。这是期望的行为吗?相关的(但更简单):对于参数{'a':{'B':'C'}}和{'a':'F'},它返回与OP函数不同的结果。不过,我不确定OP是否仔细考虑过这个例子。是的,你是对的,这就是我所说的,当听写有不同深度时的行为。你必须定义你自己的。我只返回第一个非None
A或B
。您可以执行他的代码所执行的
B或
,也可以执行任何其他冲突解决。