我试图解决一个问题,包括找到具有多个深度级别的列表的最大值。 我尝试了几个想法,但没有运气。 所以我在网上发现了这个。我自己实际上已经有了这个想法,但是我放弃了它而没有测试它,因为我之后会提到它。
def get_max(my_list):
m = None
for item in my_list:
if isinstance(item, (list, tuple)):
item = get_max(item)
if not m or m < item:
m = item
return m
示例运行:
>>> get_max(((10, (1,2), [[1],[9]])))
>>> 10
所以我放弃了这个想法,因为我认为如果在每个递归步骤中m的值被重置为None,它就不会找到我需要的最大值。 我在Python Tutor中运行它,但我仍然不明白m将如何记住值10,因为它已经多次重置为None。
有人可以向我解释一下吗?
每个递归步骤都会以某种方式创建一个新框架吗?
答案 0 :(得分:2)
每个递归步骤都会以某种方式创建一个新框架吗?
是的,每次递归调用max
都会创建一个新帧。这有实际的后果(如:如果递归深度非常大或可能无限,会发生什么?默认情况下,CPython将最大递归深度设置为1000.另请参阅:What is the maximum recursion depth in Python, and how to increase it?)
m 是一个局部变量。因此,max
的第一个父调用中的 m 与max
的子调用中分配的 m 不同。 “记住”是因为孩子 m 作为项返回给父母。
答案 1 :(得分:1)
正如其他人提到的,你的递归是正确的,因为get_max
的每个调用都有自己的局部变量,my_list
,m
和item
。
FWIW,这是您的代码的一个小变化。它应该更有效率,因为它使用内置的max
而不是使用Python循环计算最大值(尽管我们仍然在循环生成该生成器表达式)。它还消除了m = None
的需要,因此每次更新时都需要测试m
是否已初始化。
def get_max(obj):
is_seq = isinstance(obj, (list, tuple))
return max(get_max(u) for u in obj) if is_seq else obj
data = (10, (1, 2), [[1], [9], [4, 7]])
print(get_max(data))
<强>输出强>
10
我们也可以使用map
而不是max
调用中的生成器表达式来编写它。
def get_max(obj):
is_seq = isinstance(obj, (list, tuple))
return max(map(get_max, obj)) if is_seq else obj
答案 2 :(得分:0)
递归调用似乎是针对当前列表中的列表。因此,此函数的基本案例是仅包含非列表项的列表。换句话说,当找到新列表时,只有一个新的函数调用,因此只有m
变量的实例。
对get_max()
的每次调用都有自己的变量m
,该变量将在该级别及下保持最大值。