python以迭代和优雅的方式合并dict?

python以迭代和优雅的方式合并dict?,python,dictionary,Python,Dictionary,我有两条格言,比如: x = {2: {'a':1, 'b':1}} y = {3: {'a':1}, 2: {'a':2, 'c':2}} 我想要的合并结果应该是: z = {3: {'a':1}, 2: {'a':3, 'b':1, 'c':2}} 我尝试了dict(x.items()+y.items())和计数器,但只得到了 {2: {'a': 2, 'c': 2}, 3: {'a': 1}} 结果, 如何合并其值也是dict本身的dict 我已经解释了 就是我的dict值也是一个

我有两条格言,比如:

x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
我想要的合并结果应该是:

z = {3: {'a':1}, 2: {'a':3, 'b':1, 'c':2}}
我尝试了dict(x.items()+y.items())和
计数器
,但只得到了

{2: {'a': 2, 'c': 2}, 3: {'a': 1}}
结果,

如何合并其值也是dict本身的dict


我已经解释了 就是我的dict值也是一个dict。

这个呢:

对于Python2.x:

from collections import Counter

y = {2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
x = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}

t=x.copy()
print(dict({k: (dict(Counter(t.pop(k, None)) + Counter(v))) for k, v in y.items()},**t))
结果:

{1: {'a': 1, 'b': 1}, 2: {'a': 3, 'c': 2, 'b': 1}, 3: {'a': 1}}
对于Python3.5+:

{**{k: (dict(Counter(t.pop(k, None)) + Counter(v))) for k, v in y.items()},**t}

这里有一个可能的解决方案。虽然它不使用任何库,但它相当复杂

此外,它还可以与任何两本词典一起使用,这两本词典是最大的

{key: {ikey: x.get(key, {}).get(ikey, 0) + y.get(key, {}).get(ikey, 0)  
    for ikey in x.get(key, {}).keys()+y.get(key, {}).keys()} 
 for key in x.keys()+y.keys()}
输出:

{2: {'a': 3, 'b': 1, 'c': 2}, 3: {'a': 1}}

使用
collections.Counter
来“合并”要合并的项(仅公共键),并在dict理解中使用双三元表达式,在键的并集上迭代,使其他项保持不变:

import collections
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}

# pre-compute common keys, one-liners are not the ultimate goal in life!
common_keys = set(x) & set(y)

# now generate the merged dict
result = {k:collections.Counter(x[k])+collections.Counter(y[k]) if k in common_keys else x[k] if k in x else y[k] for k in set(x)|set(y)}
print(result)
结果:

{2: Counter({'a': 3, 'c': 2, 'b': 1}), 3: {'a': 1}}
注意:我们可以通过替换以下内容来避免预先计算公共密钥:

if k in common_keys


假设对于某个键的任何相同深度,在两个dict中,值的类型相同(都是dict或都是number,我不知道如何定义将数字合并为dict)

它很简单,但可能不优雅。

这一点很有效:

x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}


def key_merge (dict1, dict2):   
## function which checks for any matching keys, and merges them   
if len(dict1.keys()) == 0 or len(dict2.keys()) == 0:
    return {}
else:    
    for key in dict1.keys():
        if key in dict2.keys():
          return {key:{ k: dict1[key].get(k, 0) + dict2[key].get(k, 0) for k in set(dict1[key])|set(dict2[key]) }}

z = {**x, **y, **key_merge(x, y)}

再说一次,如果它是优雅的,由你决定

我不知道你对“优雅”的定义是什么,但假设你的意思是可读的,那么也许这种方式适合你

from collections import Counter


def counter_dict(in_dict):
    """
    Create a dict of Counters from a dict of dicts.
    """
    return dict((k, Counter(v)) for (k, v) in in_dict.items())


def merge_counter_dicts(a, b):
    """
    Create a dict of Counters from two dicts of Counters.
    Where keys exist in both counts are summed.
    """
    out_dict = a.copy()
    for k in b.keys():
        out_dict[k] = out_dict.setdefault(k, Counter()) + b[k]
    return out_dict

x = {2: {'a': 1, 'b': 1}}
y = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}

xc = counter_dict(x)
xy = counter_dict(y)

print merge_counter_dicts(xc, xy)

可能的复制品不是那个的复制品。也许是复制品,但很难找到。好问题,谢谢。但是如果y={},答案将是{},所需的应该是{2:{a':1,'b':1}}}试试这个测试用例:x={221:{bm':0.0,'tp':-144.0,'ac':9,'da':9,'bc':1,'wc':1,'bd':8}y={10:{tp 0,'ac':3,'da':294.0,'bc':1,'wc':1,'bd':2,'mk':0.0},您会发现缺少一些键。
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}


def key_merge (dict1, dict2):   
## function which checks for any matching keys, and merges them   
if len(dict1.keys()) == 0 or len(dict2.keys()) == 0:
    return {}
else:    
    for key in dict1.keys():
        if key in dict2.keys():
          return {key:{ k: dict1[key].get(k, 0) + dict2[key].get(k, 0) for k in set(dict1[key])|set(dict2[key]) }}

z = {**x, **y, **key_merge(x, y)}
from collections import Counter


def counter_dict(in_dict):
    """
    Create a dict of Counters from a dict of dicts.
    """
    return dict((k, Counter(v)) for (k, v) in in_dict.items())


def merge_counter_dicts(a, b):
    """
    Create a dict of Counters from two dicts of Counters.
    Where keys exist in both counts are summed.
    """
    out_dict = a.copy()
    for k in b.keys():
        out_dict[k] = out_dict.setdefault(k, Counter()) + b[k]
    return out_dict

x = {2: {'a': 1, 'b': 1}}
y = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}

xc = counter_dict(x)
xy = counter_dict(y)

print merge_counter_dicts(xc, xy)
# What about something like this:

# merge_nested_dicts.py

# tested under Python3.6
# assuming dict_02 overwrites dict_01
# one liner functional style
def deep_merge(dict_01, dict_02):
    return {k: {**dict_01.get(k), **dict_02.get(k)} if k in dict_01 and
                isinstance(dict_01.get(k), dict) and
                isinstance(dict_02.get(k), dict) else v 
                for k, v in {**dict_01, **dict_02}.items()}              

if __name__ == '__main__':
    y = {2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
    x = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}

    print(x)
    print(y)
    print(deep_merge(x, y))

'''
{3: {'a': 1}, 2: {'a': 2, 'c': 2}}
{2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
{3: {'a': 1}, 2: {'a': 1, 'c': 2, 'b': 1}, 1: {'a': 1, 'b': 1}}
'''