如何合并嵌套字典?

Hob*_*ack 2 python merge dictionary python-3.x

我有一个嵌套字典(python 3.9)列表,看起来像这样:

records = [
    {'Total:': {'Owner:': {'Available:': {'15 to 34 years': 1242}}}},
    {'Total:': {'Owner:': {'Available:': {'35 to 64 years': 5699}}}},
    {'Total:': {'Owner:': {'Available:': {'65 years and over': 2098}}}},
    {'Total:': {'Owner:': {'No Service:': {'15 to 34 years': 43}}}},
    {'Total:': {'Owner:': {'No Service:': {'35 to 64 years': 64}}}},
    {'Total:': {'Owner:': {'No Service:': {'65 years and over': 5}}}},
    {'Total:': {'Renter:': {'Available:': {'15 to 34 years': 1403}}}},
    {'Total:': {'Renter:': {'Available:': {'35 to 64 years': 2059}}}},
    {'Total:': {'Renter:': {'Available:': {'65 years and over': 395}}}},
    {'Total:': {'Renter:': {'No Service:': {'15 to 34 years': 16}}}},
    {'Total:': {'Renter:': {'No Service:': {'35 to 64 years': 24}}}},
    {'Total:': {'Renter:': {'No Service:': {'65 years and over': 0}}}},
]
Run Code Online (Sandbox Code Playgroud)

嵌套的级别并不总是一致的。上面的示例有 4 个级别(总计、所有者/承租人、可用/无服务、年龄组),但有些示例只有一个级别,而其他示例则有多达 5 个级别。

我想以一种不会像update()or那样替换最终字典的方式合并数据{*dict_a, **dict_b}

最终输出应如下所示:

combined = {
    'Total': {
        'Owner': {
            'Available': {
                '15 to 34 years': 1242,
                '35 to 64 years': 5699,
                '65 years and over': 2098
            },
            'No Service:': {
                '15 to 34 years': 43,
                '35 to 64 years': 64,
                '65 years and over': 5
            }
        },
        'Renter': {
            'Available': {
                '15 to 34 years': 1403,
                '35 to 64 years': 2059,
                '65 years and over': 395
            },
            'No Service:': {
                '15 to 34 years': 16,
                '35 to 64 years': 24,
                '65 years and over': 0
            }
        },
    }
}
Run Code Online (Sandbox Code Playgroud)

Sam*_*ord 6

递归是一种在任意嵌套结构上导航和操作的简单方法:

def combine_into(d: dict, combined: dict) -> None:
    for k, v in d.items():
        if isinstance(v, dict):
            combine_into(v, combined.setdefault(k, {}))
        else:
            combined[k] = v

combined = {}
for record in records:
    combine_into(record, combined)
print(combined)
Run Code Online (Sandbox Code Playgroud)
{'Total:': {'Owner:': {'Available:': {'15 to 34 years': 1242, '35 to 64 years': 5699, '65 years and over': 2098}, 'No Service:': {'15 to 34 years': 43, '35 to 64 years': 64, '65 years and over': 5}}, 'Renter:': {'Available:': {'15 to 34 years': 1403, '35 to 64 years': 2059, '65 years and over': 395}, 'No Service:': {'15 to 34 years': 16, '35 to 64 years': 24, '65 years and over': 0}}}}
Run Code Online (Sandbox Code Playgroud)

这里的总体思想是,每次调用都combine_into采用一个字典并将其组合到字典中——每个本身就是字典的值都会导致另一个递归调用,而其他值只是按原样combined复制到其中。combined

records请注意,如果某些节点对于特定节点是否是叶子存在分歧,这将引发异常(或破坏某些数据) !