转换基于中间值的循环的功能方法,该循环在python中的每个循环上更新

时间:2018-03-28 10:47:18

标签: python loops recursion functional-programming

我的标题可能不是很直接,但基本上,我想将以下使用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的两个样本项和第二个循环中的三个项的代码,但是在进入第二个循环之前需要删除第一个循环中采样的项。

我试图理解这个问题的功能方法,我该如何将其转换为递归函数?

1 个答案:

答案 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_posirrel_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函数中提供的函数,当然还有列表推导。