【问题标题】:The best way to merge multi-nested dictionaries in Python 2.7在 Python 2.7 中合并多嵌套字典的最佳方法
【发布时间】:2015-07-03 00:50:08
【问题描述】:

我有两个嵌套字典,我想将它们合并为一个(第二个字典覆盖第一个字典值)。我看到了很多合并“平面”(非嵌套)字典的漂亮解决方案,例如:

dict_result = dict1.copy()
dict_result.update(dict2)

或

dict_result = dict(dict1.items() + dict2.items())

或(我最喜欢的)

dict_result = dict(d1,**d2)

但找不到合并多嵌套字典的最有效方法。

我试图避免递归。你的提议是什么?

【问题讨论】:

  • “我试图避免递归。”祝你好运!
  • 我希望 Python 为这种情况提供了一些内置方法,但从未见过任何对我的目的有益的方法。
  • 您可以将任何递归解决方案转换为迭代解决方案,只需使用带有显式堆栈的循环......
  • 顺便说一句,你最喜欢的确实是三个中最差的,因为如果 d2 的任何键不是字符串,它就会失败。虽然第二个也不是很好,因为它构建了三个不必要的列表; dict(itertools.chain(dict1.iteritems(), dict2.iteritems())) 避免了这种情况。当然,在 90% 的情况下,您甚至不需要新的 dict,ChainMap 会更简单、更高效……但无论如何,这对于您的问题来说都是题外话。

标签: python python-2.7 dictionary merge


【解决方案1】:

除非严格限制要合并的字典的深度,否则无法避免递归。1) 此外,没有 bultin 或库函数可以执行此操作(也就是说,我不知道的),但实际上并没有那么难。应该这样做:

def merge(d1, d2):
    for k in d2:
        if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
            merge(d1[k], d2[k])
        else:
            d1[k] = d2[k]   

这是做什么的:它迭代d2中的键,如果键也可以在d1中找到并且两者都是字典,则合并这些子字典,否则用来自@的值覆盖d1中的值987654325@。请注意,这会更改d1 及其子字典就地,因此您可能需要在之前对其进行深度复制。

或使用此版本创建合并副本:

def merge_copy(d1, d2):
    return {k: merge_copy(d1[k], d2[k]) if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict) else d2[k] for k in d2}

例子:

>>> d1 = {"foo": {"bar": 23, "blub": 42}, "flub": 17}
>>> d2 = {"foo": {"bar": 100}, "flub": {"flub2": 10}, "more": {"stuff": 111}}
>>> merge(d1, d2)
>>> print d1
{'foo': {'bar': 100, 'blub': 42}, 'flub': {'flub2': 10}, 'more': {'stuff': 111}}

1)您可以使用堆栈使其迭代,但这只会使事情变得更复杂,并且应该这样做以避免最大递归深度的问题。

【讨论】:

  • 这是一个递归的就地更新,而不是像 OP 所要求的那样的递归复制合并……但如何将一个转换为另一个应该是显而易见的,即使你没有成功在你的解释中明确。 :)
  • 谢谢!但是有一点需要注意(如果有人想使用这段代码) - 在 merge_copy() 参数应该被切换,并且这个函数的正确调用应该是:merge_copy(d2, d1) :)
  • @mchfrnc 你确定吗?该功能似乎正常工作。或者只是让merge(d2, d1) 读起来更像“将 d2 合并到 d1”?我也想过,但是既然你说“第二个”应该覆盖“第一个”,我把“覆盖”这个字典放在了第二个位置。
【解决方案2】:

上述merge_copy 函数的修改版本可以被认为是合并父母和孩子,您希望父母从孩子那里继承所有值以创建新的词典。

def merge_copy(child, parent):
    '''returns parent updated with child values if exists'''
    d = {}
    for k in parent:
        if k in child and isinstance(child[k], dict) and isinstance(parent[k], dict):
            v = merge_copy(child[k], parent[k])
        elif k in child:
            v = child[k]
        else:
            v = parent[k]
        d[k] = v
    return d

【讨论】:

  • 此答案会丢弃子字典唯一的所有键,因为它迭代父级的键集,而不包括子级唯一的键。建议你遍历set().union(parent, child)
猜你喜欢
  • 1970-01-01
  • 2020-11-28
  • 2023-01-09
  • 2020-11-25
  • 2021-01-31
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多