18

我想知道在 python 中是否有等效 Haskell 的内置函数,scanl就像.reducefoldl

这样做的东西:

Prelude> scanl (+) 0 [1 ..10]
[0,1,3,6,10,15,21,28,36,45,55]

问题不在于如何实现它,我已经有 2 个实现,如下所示(但是,如果您有更优雅的实现,请随时在此处展示)。

第一次实现:

 # Inefficient, uses reduce multiple times
 def scanl(f, base, l):
   ls = [l[0:i] for i in range(1, len(l) + 1)]
   return [base] + [reduce(f, x, base) for x in ls]

  print scanl(operator.add, 0, range(1, 11))

给出:

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

第二种实现:

 # Efficient, using an accumulator
 def scanl2(f, base, l):
   res = [base]
   acc = base
   for x in l:
     acc = f(acc, x)
     res += [acc]
   return res

 print scanl2(operator.add, 0, range(1, 11))

给出:

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

谢谢 :)

4

4 回答 4

19

如果它更优雅,您可以使用它:

def scanl(f, base, l):
    for x in l:
        base = f(base, x)
        yield base

像这样使用它:

import operator
list(scanl(operator.add, 0, range(1,11)))

Python 3.x 有itertools.accumulate(iterable, func= operator.add). 它的实现如下。该实现可能会给您一些想法:

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)
    total = next(it)
    yield total
    for element in it:
        total = func(total, element)
        yield total
于 2013-01-20T11:03:25.007 回答
5

开始Python 3.8,并引入赋值表达式(PEP 572):=运算符),它提供了命名表达式结果的可能性,我们可以使用列表推导来复制左扫描操作:

acc = 0
scanned = [acc := acc + x for x in [1, 2, 3, 4, 5]]
# scanned = [1, 3, 6, 10, 15]

或者以一般的方式,给定一个列表、一个归约函数和一个初始化的累加器:

items = [1, 2, 3, 4, 5]
f = lambda acc, x: acc + x
accumulator = 0

我们可以items从左边扫描并减少它们f

scanned = [accumulator := f(accumulator, x) for x in items]
# scanned = [1, 3, 6, 10, 15]
于 2019-04-28T15:02:25.647 回答
0

我也有类似的需求。此版本使用 python 列表推导

def scanl(data):
    '''
    returns list of successive reduced values from the list (see haskell foldl)
    '''
    return [0] + [sum(data[:(k+1)]) for (k,v) in enumerate(data)]


>>> scanl(range(1,11))

给出:

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
于 2014-07-01T06:31:46.937 回答
0

像往常一样,Python 生态系统也充满了解决方案:

Toolz 有一个可以将用户提供的函数作为参数的累加器。我用 lambda 表达式对其进行了测试。

https://github.com/pytoolz/toolz/blob/master/toolz/itertoolz.py

https://pypi.python.org/pypi/toolz

和 more_itertools 一样

http://more-itertools.readthedocs.io/en/stable/api.html

我没有从 more-itertools 测试版本,但它也可以采用用户提供的功能。

于 2017-02-07T00:53:26.260 回答