【问题标题】:How to merge nested dictionaries?如何合并嵌套字典?
【发布时间】:2022-01-15 11:49:47
【问题描述】:

我有一个嵌套字典列表 (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}}}},
]

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

我想以一种不会像 update(){*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
            }
        },
    }
}

【问题讨论】:

  • StackOverflow 不是免费的编码服务。你应该try to solve the problem first。请更新您的问题以在minimal reproducible example 中显示您已经尝试过的内容。如需更多信息,请参阅How to Ask,并拨打tour :)
  • @Barmar 我将我的实际代码总结为一个非常简单的问题,并得到了预期的结果。我陈述了字典合并的两个最常见的答案以及我尝试它们时的结果。该帖子立即收到了一个答案,我现在可以解压缩,通过示例学习并应用到我的实际代码中。没有必要仅仅因为你看不到研究和总结成一个最小的、完整的和可重现的问题的工作量。
  • 你在哪里描述了你的实际代码?你只是描述了你想要的结果,你没有展示或描述你写的任何东西。

标签: python python-3.x dictionary merge


【解决方案1】:

针对这个特定示例的更直接的组合方式。

out = {}
for dct1 in records:
    for k1, dct2 in dct1.items():
        for k2, dct3 in dct2.items():
            for k3, dct4 in dct3.items():
                out.setdefault(k1,{}).setdefault(k2,{}).setdefault(k3,{}).update(dct4)

将比递归函数更快,但必须根据嵌套的深度进行更新。

【讨论】:

  • 问题的重点是它应该适用于任意级别的嵌套,因此您不能对特定的嵌套循环进行硬编码。
【解决方案2】:

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

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)
{'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}}}}

这里的总体思路是,每次调用 combine_into 都会获取一个 dict 并将其组合到 combined dict 中——每个本身是 dict 的值都会导致另一个递归调用,而其他值只是被复制到 @ 987654325@ 原样。

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

【讨论】:

    猜你喜欢
    • 2011-05-13
    • 1970-01-01
    • 2018-03-25
    • 2021-01-31
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    相关资源
    最近更新 更多