简体   繁体   English

合并Python中的字典层次结构

[英]Merging hierarchy of dictionaries in Python

I have two dictionaries, and what I'm trying to do is a bit odd. 我有两个字典,而我想做的有点奇怪。 Basically, I want to merge them. 基本上,我想将它们合并。 That's simple enough. 这很简单。 But they're hierarchies of of dictionaries, and I want to merge them in such a way that if an item in a dictionary is itself a dictionary and exists in both, I want to merge those dictionaries as well. 但是它们是字典的层次结构,我想以这样的方式合并它们:如果字典中的一项本身就是字典,并且在两者中都存在,那么我也想合并这些字典。 If it's not a dictionary, I want the values from the second dictionary to overwrite the values from the first one. 如果不是字典,我希望第二个字典中的值覆盖第一个字典中的值。 Something sort of like this: 像这样的东西:

a = {0: {0: "a"},
     1: [0, 1, 2]}

b = {0: {1: "b"},
     1: [3, 4, 5]}

Merge(a, b)

#output:
{0: {0: "a",
     1: "b"},
 1: [3, 4, 5]}

Does that make sense? 那有意义吗? Because the key "0" contained a dictionary in both a and b, it merged those dictionaries as well. 由于键“ 0”在a和b中都包含字典,因此它也合并了这些字典。 But in the case of the second key, it was a list so it just overwrote it. 但是在第二把钥匙的情况下,它是一个清单,因此只是覆盖了它。

So I suppose I'll be looking at some kind of recursive function? 所以我想我将要研究某种递归函数? Not quite sure how to approach this one. 不太确定如何处理这一问题。

Thanks! 谢谢!

Edit: I forgot to mention one pretty crucial detail: 编辑:我忘了提到一个非常关键的细节:

I need a function that works in both 2.6.2 and 2.7.3. 我需要一个在2.6.2和2.7.3中都可以使用的函数。

Assuming you might have nested dictionaries (based on your thinking in terms of recursion), something like this should work, 假设您可能嵌套了一些字典(基于您对递归的看法),那么类似的方法应该可以解决,

from copy import deepcopy

def merge(a, b):
    if isinstance(b, dict) and isinstance(a, dict):
        a_and_b = a.viewkeys() & b.viewkeys()
        every_key = a.viewkeys() | b.viewkeys()
        return {k: merge(a[k], b[k]) if k in a_and_b else 
                   deepcopy(a[k] if k in a else b[k]) for k in every_key}
    return deepcopy(b)

The return value of merge(a, b) is conceptually like creating a (deep) copy of a and running a recursive version of a.update(b) . 的返回值merge(a, b)是概念上像创建的(深)复制a和运行的递归版本a.update(b)


Using some nested examples, 使用一些嵌套的示例,

a = {0: {0: 'a'},
     1: [0, 1, 2],
     2: [9, 9],
     3: {'a': {1: 1, 2: 2}, 'b': [0, 1]}}

b = {0: {1: 'b'},
     1: [3, 4, 5],
     2: {22: 22, 33: 33},
     3: {'a': {2: 22, 3: 33}, 'b': [99, 88]}}

merge(a, b) produces, merge(a, b)产生,

{0: {0: 'a', 1: 'b'},
 1: [3, 4, 5],
 2: {22: 22, 33: 33},
 3: {'a': {1: 1, 2: 22, 3: 33}, 'b': [99, 88]}}

EDIT: Python 2.6 version 编辑:Python 2.6版本

def merge(a, b):
    if isinstance(b, dict) and isinstance(a, dict):
        a_and_b = set(a).intersection(b)
        every_key = set(a).union(b)
        return dict((k, merge(a[k], b[k]) if k in a_and_b else
                     deepcopy(a[k] if k in a else b[k])) for k in every_key)
    return deepcopy(b)

Hmm.. as long as you're not arbitrarily-nested, you don't need recursion. 嗯..只要您不是任意嵌套的,就不需要递归。

from itertools import chain

{k:(v if not isinstance(v,dict) else dict(chain(a[k].items(), v.items()))) for k,v in b.items()}
Out[10]: {0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]}

(I'm using python 3 here, feel free to replace .items with .iteritems in python 2) (我在这里使用python 3, .iteritems在python 2中.items.iteritems替换.items

Since this is a bit verbose, there's always the sneaky way to merge two dicts: 由于这有点冗长,因此总是有偷偷摸摸的方式合并两个字典:

{k:(v if not isinstance(v,dict) else dict(a[k], **v)) for k,v in b.items()}
Out[11]: {0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]}

You may or may not want to use this syntax - though it is compact, it kind of abuses cPython implementation details. 您可能会或可能不想使用此语法-尽管它很紧凑,但它会滥用cPython实现细节。

Needed something similar and implemented a more straightforward recursive solution. 需要类似的东西并实现更直接的递归解决方案。 In-place updates dict 'd'. 就地更新字典'd'。

from Collections import MutableMapping

def merge(d, v):
    """
    Merge two dictionaries.

    Merge dict-like `v` into dict-like `d`. In case keys between them are the same, merge
    their sub-dictionaries where possible. Otherwise, values in `v` overwrite `d`.
    """
    for key in v:
        if key in d and isinstance(d[key], MutableMapping) and isinstance(v[key], MutableMapping):
            d[key] = merge(d[key], v[key])
        else:
            d[key] = v[key]
    return d

Example 1: 范例1:

a = {0: {0: "a"},
     1: [0, 1, 2]}

b = {0: {1: "b"},
     1: [3, 4, 5]}

>>> merge(a, b)
{0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]}

Example 2: 范例2:

a = {0: {0: 'a'},
     1: [0, 1, 2],
     2: [9, 9],
     3: {'a': {1: 1, 2: 2}, 'b': [0, 1]}}

b = {0: {1: 'b'},
     1: [3, 4, 5],
     2: {22: 22, 33: 33},
     3: {'a': {2: 22, 3: 33}, 'b': [99, 88]}}

>>> merge(a, b) 
{0: {0: 'a', 1: 'b'},
 1: [3, 4, 5],
 2: {22: 22, 33: 33},
 3: {'a': {1: 1, 2: 22, 3: 33}, 'b': [99, 88]}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM