为什么不使用递归?使用递归程序处理递归数据结构是自然而直接的。将递归进程转换为迭代进程不需要克隆输入,创建堆栈或其他中间值。你的大脑可以摆脱这种繁琐复杂性 -
def first (a = []):
return a[0]
def rest (a = []):
return a[1:]
def myiter (a = []):
if not a:
return []
elif isinstance(first(a), list):
return [ myiter(first(a)) ] + myiter(rest(a))
else:
return [ str(first(a)) ] + myiter(rest(a))
print(myiter([1, [2, [3, 4], 5]]))
当然,在函数
f
中将
str
作为参数是有意义的。
def myiter (f, a = []):
if not a:
return []
elif isinstance(first(a), list):
return [ myiter(f, first(a)) ] + myiter(f, rest(a))
else:
return [ f(first(a)) ] + myiter(f, rest(a))
现在您可以按照自己的意愿深度映射字符串,就像这样 -
print(myiter(str, [1, [2, [3, 4], 5]]))
或者使用您选择的任何功能 -
def square (x):
return x * x
print(myiter(square, [1, [2, [3, 4], 5]]))
您是因为栈限制而试图避免递归吗? 如果使其成为尾递归 -
def identity (x):
return x
def myiter (f, init = []):
def run (a = init, then = identity):
if not a:
return \
then([])
elif isinstance(first(a), list):
return \
recur(first(a), lambda l: \
recur(rest(a), lambda r: \
then([ l ] + r)))
else:
return \
recur(rest(a), lambda r: \
then([ f(first(a)) ] + r))
return loop (run)
然后实现一个通用的loop
,将递归调用栈转换为迭代序列 -
def recur (*values):
return (recur, values)
def loop (f):
acc = f ()
while type(acc) is tuple and acc[0] is recur:
acc = f(*acc[1])
return acc
输出结果相同,但现在
myiter
可以接受任意嵌套限制的数组。不受限制地进行递归,多美妙的事情啊!
print(myiter(str, [1, [2, [3, 4], 5]]))
print(myiter(square, [1, [2, [3, 4], 5]]))
使用repl.it在您自己的浏览器中查看此程序并验证结果。
为什么不能使用递归?- Jab
@Jab,有三个原因:首先,在我的某个应用程序上经常达到最大递归限制,其次是性能问题,虽然map方法可能与迭代方式相媲美,但第三种是为了训练和学习这两种不同的编码风格。 – MarkokraM
所以你还没有达到递归限制,但你担心你的程序会吗?最好了解实际的限制而不是围绕幽灵编写程序。在使用生成器的简化实现中,请注意只有在遇到嵌套级别时才会发生递归。即使将此实现保留为原样,它也可以支持任何长度的列表以及嵌套级别高达堆栈限制,其中默认值可能约为1,000。这意味着唯一会使您的堆栈崩溃的数据输入是嵌套1000次或更多次的数据输入。直到达到实际限制之前,保留此程序可能是安全的。
def square (x):
return x * x
def myiter (f, init = []):
def gen (a):
for x in a:
if isinstance(x, list):
yield list(gen(x))
else:
yield f(x)
return list(gen(init))
print(myiter(str, [1, [2, [3, 4], 5]]))
print(myiter(square, [1, [2, [3, 4], 5]]))
a = [e]
看起来好像被误用了。你正在创建一个只包含 e 元素的列表。而get_last
最好这样写:lambda x: x[-1]
。 - Jab