如何在 Python 中递归展平嵌套的字典列表

本文介绍一种通用、可复用的递归方法,将具有深层嵌套结构(如地区层级:国家→州→城市→街道→门牌)的字典列表展平为扁平化的对象列表,保留关键字段(person/city/address/facebooklink),并确保地址路径准确反映层级关系。

在处理地理层级、组织架构或树形配置等数据时,常遇到类似 {"united states": [{"person": "...", "ohio": [...]}, ...]} 这类嵌套结构——其中每个节点既包含自身属性(如 person, address),又以同名键(如 "ohio")嵌套下级列表。目标是提取所有层级中的有效实体对象,忽略仅作容器用途的键(如 "united states"、"ohio" 等动态键名),仅保留含业务字段的字典。

以下是一个健壮、清晰的递归展平函数:

def flatten_objects(data):
    """
    递归展平嵌套字典列表,提取所有含 person/city/address/facebooklink 的叶子节点。

    Args:
        data: list 或 dict 类型的嵌套结构(支持混合嵌套)

    Returns:
        list: 扁平化后的字典列表,每个字典包含原始业务字段
    """
    result = []

    # 处理输入为列表的情况(最外层及各级子列表)
    if isinstance(data, list):
        for item in data:
            result.extend(flatten_objects(item))
        return result

    # 处理输入为字典的情况
    if isinstance(data, dict):
        # 提取当前层级的业务字段(非列表值)
        current_fields = {}
        nested_lists = {}

        for key, value in data.items():
            if isinstance(value, list):
                # 将值为列表的项暂存,后续递归处理
                nested_lists[key] = value
            else:
                # 保留基础字段(person, city, address, facebooklink 等)
                current_fields[key] = value

        # 若当前字典包含业务字段,则自身作为一条记录加入结果
        if current_fields:
            result.append(current_fields)

        # 递归处理所有嵌套列表(如 "united states": [...], "ohio": [...])
        for nested_key, nested_value in nested_lists.items():
            if isinstance(nested_value, list):
                result.extend(flatten_objects(nested_value))

    return result

使用示例:

# 示例数据(与问题中结构一致)
nested_data = [
    {
        "person": "abc",
        "city": "united states",
        "facebooklink": "link",
        "address": "united states",
        "united states": [
            {
                "person": "cdf",
                "city": "ohio",
                "facebooklink": "link",
                "address": "united states/ohio",
                "ohio": [
                    {
                        "person": "efg",
                        "city": "clevland",
                        "facebooklink": "link",
                        "address": "united states/ohio/clevland",
                        "clevland": [
                            {
                                "person": "jkl",
                                "city": "Street A",
                                "facebooklink": "link",
                                "address": "united states/ohio/clevland/Street A",
                                "Street A": [
                                    {
                                        "person": "jkl",
                                        "city": "House 1",
                                        "facebooklink": "link",
                                        "address": "united states/ohio/clevland/Street A/House 1"
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "person": "ghi",
                        "city": "columbus",
                        "facebooklink": "link",
                        "address": "united states/ohio/columbus"
                    }
                ]
            },
            {
                "person": "abc",
                "city": "washington",
                "facebooklink": "link",
                "address": "united states/washington"
            }
        ]
    }
]

# 展平并打印
flattened = flatten_objects(nested_data)
for obj in flattened:
    print(obj)

? 关键设计说明:

  • 智能识别容器键:不依赖硬编码键名(如 "united states"),而是通过 isinstance(value, list) 自动识别嵌套列表字段,适应任意层级命名;
  • 保留完整路径:address 字段已预置完整层级路径(如 "united states/ohio/clevland/Street A/House 1"),无需额外拼接;
  • 安全递归:避免无限循环,严格区分 list / dict / 基础类型,对空值或非标准结构具备鲁棒性;
  • ⚠️ 注意事项:若原始数据中存在同名但语义不同的字段(如某层 city 是字符串,另一层是对象),需按实际业务逻辑增强字段校验逻辑;
  • ? 扩展建议:如需控制输出顺序(如按 address 深度升序),可在返回前添加 sorted(flattened, key=lambda x: x.get("address", "").count("/"))。

该方案比依赖第三方库(如 flatten_json)更轻量、更可控,且完全适配此类“业务字段 + 动态容器键”混合嵌套场景,是生产环境中推荐的标准化展平实践。