在Python中总结2级嵌套字典

时间:2017-02-14 12:34:25

标签: python dictionary summary

我有2个嵌套的字典变量,它们具有相似的键,每个键都定义了不同的值:

data1 = {
"2010":{
        'A':2,
        'B':3,
        'C':5
    },
"2011":{
        'A':1,
        'B':2,
        'C':3
    },
"2012":{
        'A':1,
        'B':2,
        'C':4
    }
}

data2 = {
"2010":{
        'A':4,
        'B':4,
        'C':5
    },
"2011":{
        'A':1,
        'B':1,
        'C':3
    },
"2012":{
        'A':3,
        'B':2,
        'C':4
    }
}

在我的情况下,我需要根据相同的键对两个词典值求和,所以答案是这样的:

data3 = {
"2010":{
        'A':6,
        'B':7,
        'C':10
    },
"2011":{
        'A':2,
        'B':3,
        'C':6
    },
"2012":{
        'A':4,
        'B':4,
        'C':8
    }
}

我该怎么做?

4 个答案:

答案 0 :(得分:2)

鉴于两个词典的结构相同,您可以使用词典理解

data3 = {key:{key2:val1+data2[key][key2] for key2,val1 in subdic.items()} for key,subdic in data1.items()}

在repl中:

>>> {key:{key2:val1+data2[key][key2] for key2,val1 in subdic.items()} for key,subdic in data1.items()}
{'2010': {'B': 7, 'C': 10, 'A': 6}, '2012': {'B': 4, 'C': 8, 'A': 4}, '2011': {'B': 3, 'C': 6, 'A': 2}}

理解如下:在外环中,我们迭代key,subdic的{​​{1}}。因此,在您的情况下,data1是一年,key是该年的字典(subdic)。

现在,对于这些年中的每一年,我们迭代data1的项目,此处subdickey2'A''B''C'是我们在val1中为这些键找到的值。我们通过查询data1得到了另一个值。我们总结一下并为此构建新的词典。

答案 1 :(得分:1)

另一种解决方案:) 您还可以使用zipdata1循环中同时获取data2for,然后使用collections.Counter添加每个dicts的值。< / p>

from collections import Counter

>> {k1: Counter(v1) + Counter(v2) for (k1, v1), (k2, v2) in zip(sorted(data1.items()), sorted(data2.items()))}
{'2011': Counter({'C': 6, 'B': 3, 'A': 2}), '2010': Counter({'C': 10, 'B': 7, 'A': 6}), '2012': Counter({'C': 8, 'A': 4, 'B': 4})}

您将以Counter dict结束,但由于它是dict的子类,您仍然可以使用与常规dict相同的方法。

答案 2 :(得分:1)

如果你将dict()添加到MaxChrétiens的上面的简短解决方案中,你最终会得到常规字典:

def sum_two_nested_dicts(d1, d2):
    dicts = [d1, d2]
    d_sum = {}
    for topkey in dicts[0]:
        if topkey in dicts[1]:
            d_sum[topkey] = {}
            for key in dicts[0][topkey]:
                if key in dicts[1][topkey]:
                    new_val = sum([d[topkey][key] for d in dicts])
                    d_sum[topkey][key] = new_val
    return d_sum


data1 = {
    "2010": {
        'A': 2,
        'B': 3,
        'C': 5
    },
    "2011": {
        'A': 1,
        'B': 2,
        'C': 3
    },
    "2012": {
        'A': 1,
        'B': 2,
        'C': 4,
        'X': 111111
    },
    "1999": {
        'Z': 999999
    }
}

data2 = {
    "2010": {
        'A': 4,
        'B': 4,
        'C': 5
    },
    "2011": {
        'A': 1,
        'B': 1,
        'C': 3
    },
    "2012": {
        'A': 3,
        'B': 2,
        'C': 4
    }
}

data3 = sum_two_nested_dicts(data1, data2)

print(data3)

# different order of arguments

data4 = sum_two_nested_dicts(data2, data1)

print(data4)

# {'2010': {'C': 10, 'A': 6, 'B': 7}, '2012': {'C': 8, 'A': 4, 'B': 4}, '2011': {'C': 6, 'A': 2, 'B': 3}}
# {'2010': {'C': 10, 'A': 6, 'B': 7}, '2012': {'C': 8, 'A': 4, 'B': 4}, '2011': {'C': 6, 'A': 2, 'B': 3}}

但是,只有当两个词典共享完全相同的键时,这才能正常工作。如果两个词典都没有共享任何键,Willem Van Onsem的解决方案将无效(这将导致错误,而MaxChrétiens的解决方案将在这种情况下错误地合并项目)。现在你提到你使用的JSON数据总是包含相同的结构和类似的键,所以这不应该成为一个问题,MaxChrétien的解决方案应该可以很好地工作。

如果您确实只想确保使用两个字典(及其子字典)共享的密钥,以下内容将起作用。请注意我是如何将'X':111111作为键值对添加到2012子字典,将“1999”:{'Z':999999}添加为整个子字典。

def sum_nested_dicts(dic1, dic2):
    # create list of both dictionaries
    dicts = [dic1, dic2]
    # create a set of all unique keys from both dictionaries
    topkeys = set(sum([list(dic.keys()) for dic in dicts], []))
    # this is the merged dictionary to be returned
    d_sum = {}
    for topkey in topkeys:
        # if topkey is shared by both dictionaries
        if topkey in dic1 and topkey in dic2:
            d_sum[topkey] = {}
            keys = set(sum([list(dic[topkey].keys()) for dic in
                            dicts], []))
            for key in keys:
                # if key is shared by both subdictionaries
                if key in dic1[topkey] and key in dic2[topkey]:
                    new_val = sum([d[topkey][key] for d in dicts])
                    d_sum[topkey][key] = new_val
                # if key is only contained in one subdictionary
                elif key in dic1[topkey]:
                    d_sum[topkey][key] = dic1[topkey][key]
                elif key in dic2[topkey]:
                    d_sum[topkey][key] = dic2[topkey][key]
        # if topkey is only contained in one dictionary
        elif topkey in dic1:
            d_sum[topkey] = dic1[topkey]
        elif topkey in dic2:
            d_sum[topkey] = dic2[topkey]
    return d_sum

我意识到这远不是那么简洁和优雅,但正如我已经写过的那样,我在这里发布它以防有人试图实现这一特定功能。

长而臃肿的版本,它保留了未共享的键/值,只是因为我已经编写了它...

[

请参阅Crystal的解决方案,了解迄今为止发布的最简洁,最实用的解决方案。

答案 3 :(得分:1)

我希望这会有所帮助:

    data1 = { "2010":{ 'A':2, 'B':3, 'C':5 }, "2011":{ 'A':1, 'B':2, 'C':3 }, "2012":{ 'A':1, 'B':2, 'C':4 } } 
    data2 = { "2010":{ 'A':4, 'B':4, 'C':5 }, "2011":{ 'A':1, 'B':1, 'C':3 }, "2012":{ 'A':3, 'B':2, 'C':4 } }

    data3 = {}

    for data in [data1,data2]:
        for year in data.keys():
                for x,y in data[year].items():
                    if not year in data3.keys():
                        data3[year] = {x:y}
                    else:
                        if not x in data3[year].keys():
                            data3[year].update({x:y})
                        else:
                            data3[year].update({x:data3[year][x] + y})
    print data3

这适用于内部和外部词典的任意长度。