最简单的方法来汇总嵌套字典列表

时间:2019-05-16 21:10:21

标签: python list dictionary nested python-3.6

是否有一种更干净/更Python化的方式来累加嵌套字典列表的内容?这是我正在做的事情,但我怀疑可能会有更好的方法:

list_of_nested_dicts = [{'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}},
                        {'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}},
                        {'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}},
                        {'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}}]

total_counts = {k:{'TP': 0, 'FP': 0, 'FN': 0} for k in list_of_nested_dicts[0].keys()}

for d in list_of_nested_dicts:
    for label,counts_dict in d.items():
        for k,v in counts_dict.items():
            total_counts[label][k] += v

print(total_counts)

(假设所有键完全相同,但是值可以是任何整数)

2 个答案:

答案 0 :(得分:3)

使用collections可以使代码更严格(与@blhsing相似)

import collections

counts = collections.defaultdict(collections.Counter)
for d in list_of_nested_dicts:
    for k, v in d.items():
        counts[k].update(v)

这将为您提供默认的计数器而不是仅是dict,但是它们的行为类似。如果需要,您还可以在末尾将它们显式转换为字典。

{'class1': {'FN': 8, 'FP': 0, 'TP': 4},
 'class2': {'FN': 0, 'FP': 0, 'TP': 0},
 'class3': {'FN': 0, 'FP': 0, 'TP': 0},
 'class4': {'FN': 8, 'FP': 0, 'TP': 4}}

vs

defaultdict(<class 'collections.Counter'>,
            {'class1': Counter({'FN': 8, 'TP': 4, 'FP': 0}),
             'class2': Counter({'TP': 0, 'FP': 0, 'FN': 0}),
             'class3': Counter({'TP': 0, 'FP': 0, 'FN': 0}),
             'class4': Counter({'FN': 8, 'TP': 4, 'FP': 0})})

答案 1 :(得分:2)

您的代码中有一个明显的“不洁”之处是,您在total_counts的初始化过程中硬编码了子命令的键。您可以使用dict.setdefaultdict.get方法来避免这种硬编码,因为您可以遍历子字典的各项:

total_counts = {}
for d in list_of_nested_dicts:
    for label, counts_dict in d.items():
        for k, v in counts_dict.items():
            total_counts[label][k] = total_counts.setdefault(label, {}).get(k, 0) + v