Pythonic 通过累积和任意 lambda 函数减少?

gee*_*ose 5 python reduce lambda functional-programming accumulate

用累积执行减少的 Pythonic 方式是什么?

例如,将RReduce(). 给定一个列表和一个任意的 lambda 函数,它允许通过设置accumulate=T. 一个简单的乘法作为 lambda 函数的例子是(取自这个答案):

Reduce(`*`, x=list(5,4,3,2), accumulate=TRUE)
# [1]   5  20  60 120
Run Code Online (Sandbox Code Playgroud)

可以使用任意 lambda 函数(如lambda x, y: ...)很重要,因此允许例如仅使用总和、乘法或其他方法的解决方案将无法解决问题。我无法想出一个 Pythonic 解决方案来做到这一点,例如 Python 的itertoolsor functools,但可能有一种方法。尽管还有许多关于使用 Python 减少和专门积累的其他问题和答案,但到目前为止我还没有找到通用的答案。

一个使用循环执行累积归约的非 Pythonic 示例与任意 lambda 函数可能如下所示:

# the source list
l = [0.5, 0.9, 0.8, 0.1, 0.1, 0.9]
# the lambda function for aggregation can be arbitrary
# this one is just made up for the example
func = lambda x, y: x * 0.65 + y * 0.35 

# the accumulated reduce:
# a) the target list with initializer value hardcoded
l2 = [l[0]]
# b) the loop
for i in range(1, len(l)):
    l2 += [func(
            l2[i-1],    # last value in l2
            l[i]        # new value from l   
            )]
Run Code Online (Sandbox Code Playgroud)

那么:您将如何以 Pythonic 的方式使用累积和任意 lambda 函数进行 reduce 呢?

Gra*_*her 5

在 Python 3(在 3.2 中引入,能够传递在 3.3 中添加的函数)中,这已经在itertools.accumulate. 只需像这样使用它:

from itertools import accumulate
list(accumulate([5, 4, 3, 2], lambda a, b: a*b))
# [5, 20, 60, 120]
Run Code Online (Sandbox Code Playgroud)

如果您使用的是较早的 Python 版本,或者想自己实现它,并且您确实希望任意lambda(需要两个参数)工作,那么您可以使用上述文档中提供的生成器:

def accumulate(iterable, func=operator.add):
    'Return running totals'
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
    it = iter(iterable)
    try:
        total = next(it)
    except StopIteration:
        return
    yield total
    for element in it:
        total = func(total, element)
        yield total
Run Code Online (Sandbox Code Playgroud)

用法和上面完全一样。


如果您正在使用numpy,那么存在一个更快的解决方案,至少对于所有numpy.ufuncs。这些包括与标准库模块math提供的基本相同的功能,然后是一些。您可以在此处找到完整列表。

每个numpy.ufunc都有accumulate方法,所以你可以这样做:

import numpy as np
np.multiply.accumulate([5, 4, 3, 2])
# array([  5,  20,  60, 120])
Run Code Online (Sandbox Code Playgroud)