Python:在功能上合并两个迭代器,其中一个迭代器是递归的

Python: Functionally Merging Two Iterators Where One is Recursive

相关问题 How do I merge two python iterators? 适用于两个独立的迭代器。但是,我一直无法找到或想到合并两个迭代器所必需的工具,其中一个迭代器是递归的,并且将另一个迭代器作为输入。我有迭代器 stuff 这是一个简单的列表。然后我有迭代器 theta,它接受一个函数 func 并产生 x、func(x)、func(func(x)),其中 func 的输入之一是stuff。我已经用可变状态解决了这个问题,如下所示:

theta = some_initial_theta
for thing in stuff:
    theta = update_theta(theta, thing)
return theta

这种格式的具体例子:

def update_theta(theta, thing):
    return thing * 2 + theta

stuff = [100, 200, 300, 400]


def my_iteration():
    theta = 0
    for thing in stuff:
        theta = update_theta(theta, thing)
    print(theta)
# This prints 2000

我敢肯定,没有可变状态和 for 循环,有一种优雅的方法可以做到这一点。一个简单的 zip 不适合我,因为 theta 迭代器使用它的前一个元素作为下一个元素的输入。

表达 theta 的一种优雅方式是使用 more_itertools package:

中可用的 iterate 方法
iterate(lambda theta: update_theta(theta, thing), some_initial_theta)

然而,这样做的问题是 thing 将在整个迭代过程中得到修复。可以通过传入整个列表 stuff 然后 return 来自 update_theta 方法的其余部分来处理这个问题:

iterate(lambda theta: update_theta(theta[0], theta[1]), (some_initial_theta, stuff))

但是,我真的不想修改 update_theta 方法来获取它不感兴趣的整个列表并处理 return 该列表尾部的机制。虽然它在编程上并不困难,但关注点分离很差。 update_theta 不应该知道或关心整个列表 stuff

正如 Peter Wood 在评论中所建议的那样,这 正是 内置函数 reduce 的作用:

result = reduce(update_theta, stuff, some_initial_theta)

在 Python 3 中,reduce 已移至 functools.reduce,因此您需要导入:

from functools import reduce

如果你想要一个所有中间值的迭代器,Python3提供itertools.accumulate。没有指定初始值的参数,因此您需要将初始值放入迭代器中:

from itertools import accumulate, chain
result_iterator = accumulate(chain([some_initial_theta], stuff), update_theta)

Python 2 没有 itertools.accumulate,但您可以从 Python 3 文档中复制等效代码。没有简单的方法可以根据 Python 2 标准工具来制定它,这就是人们首先希望将它添加到 Python 3 的原因。