【问题标题】:Merging dict of dicts and sum values合并dicts和sum值的dict
【发布时间】:2019-01-22 10:18:56
【问题描述】:

我正在寻找一种将多个字典相互合并的方法,其中也包含嵌套的字典。嵌套字典的数量不是静态的,而是动态的。

最后,Final dict 应该包含所有 dicts 的 dicts 及其值的总和:

COUNTRY1 = {'a': {'X': 10, 'Y': 18, 'Z': 17}, 'b': {'AA':{'AAx':45,'AAy':22},'BB':{'BBx':45,'BBy':22}}, 'c': 100}
COUNTRY2 = {'a': {'U': 12, 'V': 34, 'W': 23}, 'b': {'AA':{'AAz':23,'AAa':26},'BB':{'BBz':11,'BBa':15}}, 'c': 115}
COUNTRY3 = {'a': {'Y': 15, 'Z': 14, 'X': 12}, 'b': {'AA':{'AAx':45,'AAz':22},'BB':{'BBy':45,'BBz':22}}, 'c': 232}

# After merging the dictionaries the result should look like:
ALL
>>> {'a': {'X': 22, 'Y': 33, 'Z': 31, 'U': 12, 'V': 34, 'W': 23}, 'b': {'AA':{'AAx':90,'AAy':22,'AAz':45,'AAa':26},'BB':{'BBx':45,'BBy':67, 'BBz':33,'BBa':15}}, 'c': 447}

我尝试了以下代码,它允许嵌套字典最多 3 个嵌套字典。不幸的是,代码没有达到我的预期。因此它看起来不是很干净,我觉得这可以用递归函数来完成,但是我找不到办法。

COUNTRIES = ['COUNTRY1','COUNTRY2', 'COUNTRY3']
ALL = {}
for COUNTRY_CODE in COUNTRIES:

    COUNTRY = pickle.load(open(COUNTRY_CODE+".p", "rb"))
    keys = COUNTRY.keys()
    for key in keys:
        try:
            keys2 = COUNTRY[key].keys()
            print(key, keys2)

            for key2 in keys2:
                try:
                    keys3 = COUNTRY[key][key2].keys()
                    print(key2, keys3)

                    for key3 in keys3:
                        try:
                            keys4 = COUNTRY[key][key2][key3].keys()
                            print(key3, keys4)
                        except:
                            print(key3, "NO KEY3")
                            if not key3 in ALL[key][key2]:
                                ALL[key][key2][key3] = COUNTRY[key][key2][key3]
                            else:
                                ALL[key][key2][key3] =+ COUNTRY[key][key2][key3]

                except:
                    print(key2, "NO KEY2")
                    if not key2 in ALL[key]:
                        ALL[key][key2] = COUNTRY[key][key2]
                    else:
                        ALL[key][key2] =+ COUNTRY[key][key2]

        except:
            print(key, "NO KEY")
            if not key in ALL:
                ALL[key] = COUNTRY[key]
            else:
                ALL[key] =+ COUNTRY[key]

print(ALL)

【问题讨论】:

  • 你试过什么?请粘贴一些东西。
  • 我刚刚将我的代码添加到帖子中。
  • 你的代码哪里出错了?你当前的输出是什么样的?
  • 如果不同字典中的键是唯一的,则代码似乎可以工作,但是如果键相同,第二个字典将覆盖第一个字典的值

标签: python python-3.x dictionary merge


【解决方案1】:

问题是您需要根据值的类型确定如何处理字典键。基本思路是:

  • 输入是一对字典,输出是和字典
  • 遍历两个输入字典
  • 如果值是字典,则递归
  • 如果一个值是一个数字,将它添加到另一个数字中

这很容易通过理解来实现:

def add_dicts(d1, d2):
    def sum(v1, v2):
        if v2 is None:
            return v1
        try:
            return v1 + v2
        except TypeError:
            return add_dicts(v1, v2)
    result = d2.copy()
    result.update({k: sum(v, d2.get(k)) for k, v in d1.items()})
    return result

该副本确保d2 中不在d1 中的所有键都被简单地复制。

你现在可以总结如下:

ALL = add_dicts(add_dicts(COUNTRY1, COUNTRY2), COUNTRY3)

更一般地,您可以使用functools.reduce 对不定数量的字典执行此操作:

dicts = [COUNTRY1, COUNTRY2, COUNTRY3]
ALL = reduce(add_dicts, dicts)

【讨论】:

    【解决方案2】:

    制作如下两个函数:

    def cal_sum(lst):
        final_dict = dict()
        for l in lst:
            sum(final_dict,l)
        return final_dict
    
    def sum(final_dict,iter_dict):
        for k, v in iter_dict.items():
            if isinstance(v, dict):
                sum(final_dict.setdefault(k, dict()), v)
            elif isinstance(v, int):
                final_dict[k] = final_dict.get(k, 0) + v
    

    如下调用上述代码会产生所需的输出:

    >>> print(cal_sum([COUNTRY1, COUNTRY2, COUNTRY3]))
    {'a': {'U': 12, 'W': 23, 'V': 34, 'Y': 33, 'X': 22, 'Z': 31}, 'c': 447, 'b': {'AA': {'AAa': 26, 'AAy': 22, 'AAx': 90, 'AAz': 45}, 'BB': {'BBa': 15, 'BBz': 33, 'BBy': 67, 'BBx': 45}}}
    

    【讨论】:

    • 另一个看起来很干净的答案,但这在 Python 3.6 中对我不起作用。我认为 Python 3 中的字典不再允许使用 iteritems()?
    • @Sem 已更新答案。检查它现在是否有效?
    • 由于某种原因,运行此代码后,一些嵌套的 dicts 为空。我现在会坚持使用@Mad Physicist 的代码,不过感谢您的努力!
    • 对于您问题中的输入,它工作正常。你能列出导致问题的字典吗?
    • 我发现这是因为我的 dicts 中的某些值是浮点数而不是整数。我将最后一个 elif 更改为: elif isinstance(v, int) 或 isinstance(v, float): 解决了问题。我喜欢这个解决方案,因为我可以为每种类型指定如何处理数据,这可能比@Mad Physicist 的解决方案更强大。
    猜你喜欢
    • 2017-07-30
    • 1970-01-01
    • 1970-01-01
    • 2020-10-15
    • 2013-05-25
    • 2014-12-17
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多