Python 递归聚合

Python recursive aggregation

我正在使用需要展平的嵌套数据结构。需要聚合这些值,以便在嵌套数据的每个级别生成总计。我正在尝试以递归方式执行此操作,但尚不清楚如何最好地实现此目的?

以下是我正在处理的数据示例。

def get_result():
    return {
        "a1": {
            "b1": {
                "c1": {
                    "d1": 1,
                    "d2": 1,
                },
                "c2": {
                    "d3": 1,
                }
            },
            "b2": {
                "c3": {
                    "d4": 1
                }
            }
        },
        "a2": {}
    }

我想要生成的数据如下:

[
    {
        "key": "a1",
        "total": 4
    },
    {
        "key": "b1",
        "total": 3
    },
    {
        "key": "c1",
        "total": 2
    },
    {
        "key": "d1",
        "total": 1
    },
    {
        "key": "d2",
        "total": 1
    }
    {
        "key": "c2",
        "total": 1
    },
    {
        "key": "d3",
        "total": 1
    },
    {
        "key": "b2",
        "total": 1
    },
    {
        "key": "c3",
        "total": 1
    },
    {
        "key": "d4",
        "total": 1
    }
]

你可以使用递归

from collections import defaultdict

def agg(data):
    result = defaultdict(int)
    agg_sum = 0
    for k, v in data.items():
        if isinstance(v, dict):
            d, sub = agg(v)
            if sub:
                result.update(d)
                result[k] += sub
                agg_sum += sub
        else:
            result[k] += v
            agg_sum += v
    return result, agg_sum

您可以使用递归生成器函数来获得更短的解决方案:

d = {'a1': {'b1': {'c1': {'d1': 1, 'd2': 1}, 'c2': {'d3': 1}}, 'b2': {'c3': {'d4': 1}}}, 'a2': {}}
def get_aggr(d):
   return d if not isinstance(d, dict) else sum(map(get_aggr, d.values()))

def aggr_keys(d):
   for a, b in d.items():
      yield {'key':a, 'total':get_aggr(b)}
      yield from (() if not isinstance(b, dict) else aggr_keys(b))

print(list(aggr_keys(d)))

输出:

[{'key': 'a1', 'total': 4}, 
 {'key': 'b1', 'total': 3},  
 {'key': 'c1', 'total': 2}, 
 {'key': 'd1', 'total': 1}, 
 {'key': 'd2', 'total': 1}, 
 {'key': 'c2', 'total': 1}, 
 {'key': 'd3', 'total': 1}, 
 {'key': 'b2', 'total': 1}, 
 {'key': 'c3', 'total': 1}, 
 {'key': 'd4', 'total': 1}, 
 {'key': 'a2', 'total': 0}]