Python代码阅读(第35篇):完全(深度)展开嵌套列表

Python:完全展开嵌套列表的实现
本文探讨了Python代码实现将嵌套列表完全展开为简单列表的方法,源自30-seconds-of-python。通过递归函数和列表推导式,检查元素是否可迭代并逐层展开嵌套层次。

Python 代码阅读合集介绍:为什么不推荐Python初学者直接看项目源码

本篇阅读的代码实现了将一个嵌套列表的所有嵌套层次完全展开,形成一个简单的列表的功能。

本篇阅读的代码片段来自于30-seconds-of-python

deep_flatten

from collections.abc import Iterable

def deep_flatten(lst): 
  return [a for i in lst for a in deep_flatten(i)] if isinstance(lst, Iterable) else [lst]

# EXAMPLES
deep_flatten(<
<think> 我们面对的问题:如何在深度优先遍历嵌套字典的同时修改字典的键。 引用中提到了使用深度优先遍历(如引用[1]和[4])来处理嵌套结构(字典和列表)。但是,我们还需要在遍历过程中修改键。 注意: 1. 在遍历过程中修改字典的键需要谨慎,因为直接修改键可能会导致迭代出现问题(比如字典在迭代时能直接修改键)。 2. 一种可行的方法是先遍历整个数据结构,记录需要修改的键值对,然后在遍历结束后进行修改。但是这样可能需要额外的空间,并且如果嵌套很深,操作可能复杂。 3. 另一种方法是在深度优先遍历的过程中重建新的字典,这样在遍历的过程中就可以对键进行修改(例如,使用递归函数返回一个新的字典,其中键已经被修改)。 我们选择第二种方法:重建一个新的字典。这样避免了在遍历过程中修改原字典带来的问题。 思路: 我们设计一个递归函数,它接受一个字典(或列表)作为输入,然后返回一个新的字典(或列表),其中所有的键都按照某种规则进行了修改。 具体步骤: 1. 如果当前节点是字典,我们就创建一个新的空字典。 2. 遍历原字典的每一个键值对: a. 对键进行修改(比如应用一个转换函数)。 b. 对值进行判断: - 如果值是字典,则递归处理这个字典。 - 如果值是列表,则递归处理这个列表(因为列表中可能包含字典)。 - 否则,直接使用原值。 3. 如果是列表,则遍历列表的每一个元素,对每个元素同样递归处理(因为元素可能是字典或列表)。 注意:在修改键时,我们需要一个规则(比如将键转换为大写,或者添加前缀等)。这里我们假设有一个函数`transform_key(key)`用于修改键。 代码示例: ```python def transform_dict(obj, transform_func): """ 深度优先遍历字典和列表,对字典的键进行转换。 :param obj: 当前对象,可以是字典、列表或其他类型。 :param transform_func: 对键进行转换的函数。 :return: 返回转换后的新对象。 """ if isinstance(obj, dict): new_dict = {} for key, value in obj.items(): # 转换键 new_key = transform_func(key) # 递归处理值 new_dict[new_key] = transform_dict(value, transform_func) return new_dict elif isinstance(obj, list): new_list = [] for item in obj: new_list.append(transform_dict(item, transform_func)) return new_list else: # 如果是其他类型,直接返回 return obj ``` 使用示例: ```python # 假设我们有一个嵌套字典 data = { "name": "Alice", "address": { "street": "Main St", "city": "Boston" }, "friends": [ {"name": "Bob", "age": 30}, {"name": "Charlie", "age": 35} ] } # 定义一个转换函数,比如将键转换为大写 def to_upper(key): return key.upper() # 转换 new_data = transform_dict(data, to_upper) print(new_data) ``` 输出: ```plaintext { 'NAME': 'Alice', 'ADDRESS': {'STREET': 'Main St', 'CITY': 'Boston'}, 'FRIENDS': [ {'NAME': 'Bob', 'AGE': 30}, {'NAME': 'Charlie', 'AGE': 35} ] } ``` 注意事项: 1. 这个函数会递归遍历所有的字典和列表,直到遇到基本数据类型(字符串、整数等)为止。 2. 转换函数`transform_func`需要根据需求自定义。 如果原始数据结构中包含自定义对象或其他非字典和列表的集合类型,上面的函数可能够,需要根据实际情况扩展。 引用中的iter_node方法(引用[1])是用于遍历并记录路径,而我们的目标是修改键。因此,我们采用了深度优先遍历并重建字典的方法。 引用[5]展示了数组扁平化的深度优先遍历,虽然问题同,但递归思想类似。 这样,我们就实现了在深度优先遍历嵌套字典的同时修改字典的键。 </think> ### Python深度优先遍历嵌套字典并修改字典键的方法 要在深度优先遍历嵌套字典的同时修改字典键,可以采用递归方法遍历数据结构,并在遍历过程中重建新的字典结构。以下是实现方法: ```python def transform_keys(data, key_map=None): """ 深度优先遍历嵌套字典/列表,并修改字典键 :param data: 输入数据(字典/列表/基础类型) :param key_map: 键转换函数,默认为大小写转换 :return: 转换后的新数据结构 """ # 默认转换函数:将键转为大写 if key_map is None: key_map = lambda k: k.upper() # 处理字典类型 if isinstance(data, dict): new_dict = {} for key, value in data.items(): new_key = key_map(key) # 应用键转换 # 递归处理值 new_dict[new_key] = transform_keys(value, key_map) return new_dict # 处理列表类型 elif isinstance(data, list): return [transform_keys(item, key_map) for item in data] # 基础类型直接返回 else: return data ``` #### 使用示例 ```python # 原始嵌套字典 original = { "user": { "firstName": "John", "contacts": [ {"type": "email", "value": "john@example.com"}, {"type": "phone", "value": "123-4567"} ], "metadata": {"version": 1.0} } } # 转换键为大写 transformed = transform_keys(original) print(transformed) # 自定义转换函数(添加前缀) prefixed = transform_keys(original, lambda k: "key_" + k) print(prefixed) ``` #### 输出结果 ```json { "USER": { "FIRSTNAME": "John", "CONTACTS": [ {"TYPE": "email", "VALUE": "john@example.com"}, {"TYPE": "phone", "VALUE": "123-4567"} ], "METADATA": {"VERSION": 1.0} } } ``` ### 关键实现说明: 1. **递归深度优先遍历**: - 遇到字典时遍历所有键值对 - 遇到列表时遍历所有元素 - 基础类型直接返回 2. **键修改逻辑**: - 在递归处理值之前,先对当前键进行转换 - 使用`key_map`函数实现灵活的键转换规则 3. **安全修改**: - 创建新字典而非修改原字典,避免迭代冲突 - 保持原始数据的可变性[^1] 4. **支持嵌套结构**: - 自动处理字典嵌套列表列表嵌套字典等复杂结构 - 递归深度仅受Python递归限制影响[^4] ### 注意事项: 1. 当处理超大嵌套结构时,可改用迭代DFS避免递归深度限制 2. 键转换函数应保证输出键的可哈希性 3. 原始数据中的列表顺序会被保留,但字典顺序取决于Python版本(3.7+保序)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值