🍉 CSDN 叶庭云https://yetingyun.blog.csdn.net/


任务:编写一个递归函数来遍历 JSON 数据并获取所有 key 路径的组合

具体实现:

  • 为了达成这一需求,我们可以编写一个递归函数来遍历 JSON 数据的每个层级。该函数将利用 yield 关键字来逐个生成每个键的路径及其对应的值。
  • 在处理过程中,我们将特别关注字典、列表和元组这三种数据类型,它们是构建 JSON 数据的基础。该函数首先会检查输入的 data 是否为字典、列表或元组。对于字典,函数将遍历每个键值对,并递归地调用自身来处理对应的值。若这些值属于基本数据类型,函数将生成包含当前完整路径和该值的元组。对于列表或元组,该函数将通过索引来标识每个元素的路径,并同样递归地处理每一个元素。
  • 利用 yieldyield from 语句,这种方法能高效处理大型 JSON 数据,它通过逐步生成每个结果,从而无需一次性将所有数据加载到内存中。

补充一个知识点,在 Python 编程语言中,基本数据类型包括以下几种:

  1. 整数 (int):表示整数值,例如 1, -2, 100
  2. 浮点数 (float):表示小数值,例如 3.14, -0.001, 1.0
  3. 布尔值 (bool):表示真或假,只有两个值 TrueFalse
  4. 字符串 (str):表示文本数据,例如 "Hello, World!", 'Python'
  5. 列表 (list):有序的可变集合,例如 [1, 2, 3], ['a', 'b', 'c']
  6. 元组 (tuple):有序的不可变集合,例如 (1, 2, 3), ('a', 'b', 'c')
  7. 集合 (set):无序的唯一元素集合,例如 {1, 2, 3}, {'a', 'b', 'c'}
  8. 字典 (dict):键值对的对应关系,例如 {'name': 'Alice', 'age': 25}
  9. 字节 (bytes):表示字节数据,例如 b'Hello', b'\x00\x01\x02'
  10. 字节数组 (bytearray):可变的字节数组,例如 bytearray(b'Hello')
  11. 复数 (complex):表示复数,例如 3 + 4j, -1.5 + 2.3j
  12. NoneType (None):表示空值或缺失值,只有一个值 None

这些数据类型在 Python 中用于不同的数据处理和存储需求。

代码示例 1,基础版 Python 代码:

def json_key_paths(json_obj, parent_path=""):
    """
    实现了一个递归函数 json_key_paths,用于遍历 JSON 对象并生成所有键的路径及其对应的值。

    输入:
         - json_obj:待遍历的 JSON 对象
         - parent_path:当前路径的前缀,默认为空字符串。
    输出:
         - 键的路径及其对应的值
    """
    if isinstance(json_obj, dict):  # 检查 json_obj 是否为字典类型。如果是字典,则遍历其键值对。
        for k, v in json_obj.items():
            # 构建当前层的路径,如果 parent_path 不为空,则在其后添加键 k,否则直接使用键 k。
            current_path = f"{parent_path}.{k}" if parent_path else k
            # 如果值 v 是字典、列表或元组,递归调用 json_key_paths;否则,生成当前路径和值的元组。
            if isinstance(v, (dict, list, tuple)):
                yield from json_key_paths(v, current_path)
            else:
                # 如果是基本数据类型,则产生当前路径
                yield current_path, v

    elif isinstance(json_obj, (list, tuple)):  # 检查 json_obj 是否为列表或元组类型。如果是列表或元组,遍历其元素。
        for index_, v in enumerate(json_obj, start=0):
            # 构建当前层的路径,使用索引 index_。
            current_path = f"{parent_path}[{index_}]"
            # 如果值 v 是字典、列表或元组,递归调用 json_key_paths;否则,生成当前路径和值的元组。
            if isinstance(v, (dict, list, tuple)):
                yield from json_key_paths(v, current_path)
            else:
                yield current_path, v


# 示例 JSON 数据
json_example = {
    "name": "John",
    "age": 30,
    "languages": ["English", "French"],
    "address": {"street": "1234 Elm St", "city": "Somewhere"},
    "cars": {
        "Nissan": ["Altima", "Leaf", "Maxima"],
        "Ford": {"Sedan": "Fiesta", "Truck": "F-150", "SUV": "Explorer"},
    },
    "isActive": True,
}
json_example = {
    "company": {
        "name": "Tech Innovations",
        "address": {
            "street": "123 Tech Lane",
            "city": "Innovation City",
            "state": "Tech State",
            "zip": "12345",
            "country": "Techland",
            "coordinates": {
                "latitude": "40.7128",
                "longitude": "-74.0060",
                "mapLink": "https://maps.google.com/?q=40.7128,-74.0060",
            },
        },
        "departments": {
            "engineering": {
                "manager": "John Doe",
                "employees": {"employee1": "Jane Smith", "employee2": "Bob Johnson"},
            },
            "marketing": {
                "manager": "Alice Brown",
                "employees": {"employee1": "Charlie Davis", "employee2": "Diana Evans"},
            },
            "sales": {
                "manager": "Eva Ford",
                "employees": {
                    "employee1": "George Gibson",
                    "employee2": "Helen Harris",
                },
            },
        },
        "projects": {
            "project1": {
                "name": "AI Development",
                "description": "Developing advanced AI algorithms",
                "team": {
                    "lead": "Ivy Irwin",
                    "members": {"member1": "Jack Jackson", "member2": "Katie King"},
                },
            },
            "project2": {
                "name": "Cloud Solutions",
                "description": "Building scalable cloud infrastructure",
                "team": {
                    "lead": "Liam Lee",
                    "members": {"member1": "Mia Martin", "member2": "Noah Nelson"},
                },
            },
        },
    }
}

# 实际上是生成包含当前完整路径和值的元组
# for tuple_ in json_key_paths(json_example):
#     print(tuple_)
for path, value in json_key_paths(json_example):
    print(f"{path} -> {value}")

这段代码实现了一个递归函数 json_key_paths,用于遍历 JSON 对象(字典、列表或元组)并生成所有键的路径及其对应的值。具体来说,它解决了以下问题:

  • 遍历复杂结构:JSON 对象可能包含嵌套的字典、列表或元组,这个函数能够递归地遍历这些结构。
  • 生成路径:对于每个键值对,生成从根节点到当前键的路径,路径格式为字符串,便于后续处理。
  • 处理嵌套结构:对于嵌套的字典、列表或元组,递归调用自身,确保所有层级的键值对都能被遍历到。

结果如下:

在这里插入图片描述

实际上,上面的 Python 代码具有进一步优化的潜力。通过利用 collections.abc 模块中的 MappingSequence,我们可以简化类型检查的过程

collections.abc 模块是 Python 的容器抽象基类。这些抽象基类可用于判断一个具体类是否具有特定的接口,如是否可哈希或是否为映射类。Mapping:只读且可变的映射的抽象基类;Sequence:只读且可变的序列的抽象基类。抽象基类的应用:

  • 确定类和示例是否拥有特定函数,如判断对象是否可迭代、是否有键值对、是否可哈希等。
  • 可用作混入类,简化类的开发。
  • 如实现 Set API 的类只需提供 __contains__、__iter__ 和 __len__ 方法。

代码示例 2,进阶版 Python 代码:

# 从 collections.abc 导入 Mapping 和 Sequence,用于类型检查。
from collections.abc import Mapping, Sequence


def json_key_paths(json_obj, parent_path=""):
    # 定义 base_data_type 元组,包含基本数据类型,用于排除这些类型以避免递归。
    base_data_type = (int, float, str, bool, bytes, complex, type(None))
    # 如果 json_obj 算是 Mapping 类型,遍历其键值对。
    if isinstance(json_obj, Mapping):
        for k, v in json_obj.items():
            # 构建当前路径 current_path,如果 parent_path 不为空,则使用字符串拼接来连接路径和键。
            current_path = f"{parent_path}.{k}" if parent_path else k
            # 如果值 v 是 Mapping 或 Sequence,且不是基本数据类型,递归调用 json_key_paths。
            if isinstance(v, (Mapping, Sequence)) and not isinstance(v, base_data_type):
                yield from json_key_paths(v, current_path)
            # 否则,生成当前路径和值。
            else:
                yield current_path, v
    # 如果 json_obj 是 Sequence 且不是基本数据类型,遍历其元素。
    elif isinstance(json_obj, Sequence) and not isinstance(json_obj, base_data_type):
        for index_, v in enumerate(json_obj):
            # 构建当前路径 current_path,使用字符串拼接来连接路径和索引。
            current_path = f"{parent_path}[{index_}]"
            # 如果值 v 是 Mapping 或 Sequence,且不是基本数据类型,递归调用 json_key_paths。
            if isinstance(v, (Mapping, Sequence)) and not isinstance(v, base_data_type):
                yield from json_key_paths(v, current_path)
            # 否则,生成当前路径和值。
            else:
                yield current_path, v


json_example = {
    "company": {
        "name": "Tech Innovations",
        "address": {
            "street": "123 Tech Lane",
            "city": "Innovation City",
            "state": "Tech State",
            "zip": "12345",
            "country": "Techland",
            "coordinates": {
                "latitude": "40.7128",
                "longitude": "-74.0060",
                "mapLink": "https://maps.google.com/?q=40.7128,-74.0060",
            },
        },
        "departments": {
            "engineering": {
                "manager": "John Doe",
                "employees": {"employee1": "Jane Smith", "employee2": "Bob Johnson"},
            },
            "marketing": {
                "manager": "Alice Brown",
                "employees": {"employee1": "Charlie Davis", "employee2": "Diana Evans"},
            },
            "sales": {
                "manager": "Eva Ford",
                "employees": {
                    "employee1": "George Gibson",
                    "employee2": "Helen Harris",
                },
            },
        },
        "projects": {
            "project1": {
                "name": "AI Development",
                "description": "Developing advanced AI algorithms",
                "team": {
                    "lead": "Ivy Irwin",
                    "members": {"member1": "Jack Jackson", "member2": "Katie King"},
                },
            },
            "project2": {
                "name": "Cloud Solutions",
                "description": "Building scalable cloud infrastructure",
                "team": {
                    "lead": "Liam Lee",
                    "members": {"member1": "Mia Martin", "member2": "Noah Nelson"},
                },
            },
        },
    }
}

for path, value in json_key_paths(json_example):
    print(f"{path} -> {value}")

结果如下:

在这里插入图片描述

GitHub 加速计划 / js / json
18
5
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:2 个月前 )
960b763e 5 个月前
8c391e04 8 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐