不递归地访问嵌套列表和字典中的所有元素

Posted

技术标签:

【中文标题】不递归地访问嵌套列表和字典中的所有元素【英文标题】:visit all elements in nested lists and dicts without recursion 【发布时间】:2017-01-27 12:25:24 【问题描述】:

我有一个由嵌套列表和字典组成的结构。我想申请一个 作用于每个元素。如何在没有递归的情况下做到这一点。

def visit(data, func):
    if isinstance(data, dict):
        for k, v in data.items():
            data[k] = visit(v, func)
        return data
    elif isinstance(data, list):
        for i, v in enumerate(data):
            data[i] = visit(v, func)
        return data
    else:
        return func(data)

递归版本适用于小数据,但我遇到了 RecursionError 数据量大时异常。

我寻找消除递归的一般方法,我发现的方法依赖于 首先将递归调用转换为尾调用,我的问题是 我的示例中的递归调用在循环内。

【问题讨论】:

对于嵌套深度超过 1000 层的数据结构,您将达到递归限制,这似乎很荒谬。我怀疑实际发生的情况是您的数据中有循环。 @Zii8roZi 为什么不提高递归限制? import sys; sys.setrecursionlimit(100000) 你想达到什么目的?列表和字典应该如何处理,因为列表只包含元素,而字典提供键值对。 虽然帮助 OP 解决他们的具体问题总是好的,但这也是一个普通观众的 QA 网站。在基本算法的递归和迭代实现之间切换是一种重要的技能,对于这类网站来说也是一个很好的问题。 @Frito 这将是一个临时解决方案。如果数据再次增长,我将不得不对其进行更改。 【参考方案1】:

这种方法会奏效。不过,作为记录,我同意 Sven Marnach 的观点,如果您的嵌套打破了递归限制,那么您的数据结构肯定会出现问题。如果像 Sven 猜想的那样,您的数据中有循环,那么这种方法也会失效。

data = [1,2, 'a':1, 'b':'a':[1,2,3],3]

def apply(data, f):
    stack = []
    stack.append(data)
    while stack:
        data = stack.pop()
        if isinstance(data, dict):
            for k,v in data.items():
                if isinstance(v, (dict,list)):
                    stack.append(v)
                else:
                    data[k] = f(v)
        if isinstance(data, list):
            for i,e in enumerate(data):
                if isinstance(e, (dict,list)):
                    stack.append(e)
                else:
                    data[i] = f(e)

在解释器外壳中:

$ python -i apply.py
>>> apply(data, lambda x: x + 1)
>>> data
[2, 3, 'a': 2, 'b': 'a': [2, 3, 4], 4]
>>> 

【讨论】:

以上是关于不递归地访问嵌套列表和字典中的所有元素的主要内容,如果未能解决你的问题,请参考以下文章

递归地重命名字典列表中的字典键

如何一次对字典或列表中的所有嵌套字典和列表进行排序?

Python基础语法

如何在不停止递归的情况下返回递归函数中的值?

在嵌套列表中查找元素,但是我们不知道该列表

Day2-------列表元组字典等