我的标题可能不是很直接,但基本上,我想将以下使用for循环编写的代码更改为递归函数。
import numpy as np
irrel_pos = range(3, 11)
n_extra_pos = [2, 3]
extra_pos = []
rs = np.random.RandomState(1)
for i in range(len(n_extra_pos)):
sample_i = rs.choice(list(irrel_pos), n_extra_pos[i], replace=False)
extra_pos.append(set(sample_i))
irrel_pos = set(irrel_pos) - set(extra_pos[i])
print(irrel_pos)
print(extra_pos)
输出:
{8, 9, 3}
[{10, 5}, {4, 6, 7}]
以下是第一个循环中来自irrel_pos的两个样本项和第二个循环中的三个项的代码,但是在进入第二个循环之前需要删除第一个循环中采样的项。
我试图理解这个问题的功能方法,我该如何将其转换为递归函数?
答案 0 :(得分:4)
没有详细说明为什么你想要这样做,至少有两种不同的方法。这在很大程度上取决于你是否希望调用是一个尾调用(它允许编译器在许多严格的函数语言中优化掉函数调用 - 尽管不是Python)或者你想要一个更直接的递归函数。
直接实施
import numpy as np
def recursive(rs, n_extra_pos, irrel_pos):
if n_extra_pos == []:
return [], irrel_pos
extra_pos, irrel_pos = recursive(rs, n_extra_pos[:-1], irrel_pos)
sample = set(rs.choice(list(irrel_pos), n_extra_pos[-1], replace=False))
return extra_pos + [sample], irrel_pos - sample
irrel_pos = set(range(3, 11))
n_extra_pos = [2, 3]
rs = np.random.RandomState(1)
extra_pos, irrel_pos = recursive(rs, n_extra_pos, irrel_pos)
print(extra_pos, irrel_pos)
在这个实现中,首先我们递归调用selfelf,直到消耗了n_extra_pos
的所有元素,然后在通过调用堆栈返回时,我们进行所需的计算并更新结果。可以看出,递归调用不这里发生的最后一件事,因此TCO(尾调用优化)是不可能的。
要创建一个允许TCO的函数,我们需要使用累加器而不是首先到达调用堆栈的底部,我们将在向下的路上进行计算,所以说,在这样做时,我们将添加我们的累加器(extra_pos
和irrel_pos
)的结果。然后,当到达底部时,我们所要做的就是返回累加器。这个的实现是
import numpy as np
def tail_recursive(rs, n_extra_pos, extra_pos, irrel_pos):
if n_extra_pos == []:
return extra_pos, irrel_pos
sample = set(rs.choice(list(irrel_pos), n_extra_pos[0], replace=False))
return tail_recursive(rs, n_extra_pos[1:],
extra_pos + [sample], irrel_pos - sample)
irrel_pos = set(range(3, 11))
n_extra_pos = [2, 3]
rs = np.random.RandomState(1)
extra_pos, irrel_pos = tail_recursive(rs, n_extra_pos, [], irrel_pos)
print(extra_pos, irrel_pos)
但是,如上所述,Python中没有TCO,这使得递归函数不那么有用,从而使得Python不是使用内置map
{{1 (reduce
)和functools
函数中提供的函数,当然还有列表推导。