给定一个函数f(x)
,目标是递归调用f(x)
,但输出的内存为2步。即:
>>> def f(x): return x**2
...
>>> memory = original = 3
>>> x0 = f(original)
>>> x1 = f(x0+memory)
>>> memory = x0
>>> x2 = f(x1+memory)
>>> memory = x1
>>> x3 = f(x2+memory)
>>> memory = x2
>>> x4 = f(x3+memory)
>>> x4
307766666167459524
我可以保存一个列表,然后在递归中存储每次迭代的所有输出:
>>> original = 3
>>> memory = []
>>> memory.append(original)
>>> memory.append(f(original))
>>> for i in range(4):
... memory.append(f(memory[-1]+memory[-2]))
...
>>> memory[-1]
307766666167459524
但是想象一下,保存这些输出是一项昂贵的任务,因为我使用的实际f(x)
存储了一些巨大数量的浮点,并且它不仅仅是一个正方形。
我还可以将最后2个内存插槽存储为花哨的deque
:
>>> from collections import deque
>>> original = 3
>>> q = deque([original, f(original)])
>>> for i in range(4):
... q.append(f(q[-1]+q.popleft()))
...
>>> q[-1]
307766666167459524
我还能用某种形式的记忆机制来执行这种递归功能吗?
想象一下,如果内存更复杂,我需要存储的不只是-2而是-n而且我必须访问[-n:-1]元素?您的解决方案是否适应这种情况?
答案 0 :(得分:1)
当您必须处理无限序列时,Python生成器是一个很好的解决方案。
在您的示例中,如果您只需要访问最后两个元素,则可以使用以下生成器函数:
def f_generator(x):
l = [x, f(x)]
while True:
res = f(l[0]+l[1])
l.pop(0)
l.append(res)
yield res
outputs = f_generator(3)
for i in range(4):
print(outputs.next())
如果您需要在生成器函数中访问两个以上的元素,则需要通过将要访问的元素数量作为参数传递,并修改列表初始化(l = [x, f(x)]
)和计算下一个元素(res = f(l[0]+l[1])
)。
答案 1 :(得分:0)
这应该适合您的问题:
mem = [3,9]
表示范围(2,x)中的i:
mem.append(f(mem[-1] + mem[-2]))
# if mem have more than n elements, pop the first one
if len(mem) > n:
mem.pop(0)
答案 2 :(得分:0)
生成器听起来就像你之后的那样,因为它会懒洋洋地生成序列中的下一个元素。如果你使它足够通用,你可以稍后重复使用:
例如:
def do_on_last_n_generator(f, n, seed):
internal_list = [seed]
while True:
internal_list.append(f(internal_list, n))
if len(internal_list)>n:
internal_list.pop(0)
yield internal_list[-1]
然后你可以提供一个功能,例如
def my_sum_func(a_list, n): # sum the last n elements
return sum(a_list[-n:])
然后让自己成为一名发电机。在这里你可以决定种子数(我用1)和记忆元素(这里我用4):
sum_last_four = do_on_last_n_generator(my_sum_func, 4, 1)
然后每次你想获得下一个元素:
next_number = next(sum_last_four)
或者你可以让它们循环:
for i in range(10):
print(next(sum_last_four)
如果您稍后决定实际上想要对最后十个元素求和,那么只需创建一个新的生成器:
sum_last_ten = do_on_last_n_generator(my_sum_func, 10, 1)
您可以类似地更改功能和种子。