18

scanlに相当する Haskellと同等の python に組み込み関数があるかどうかを知りたいreduceですfoldl

これを行うもの:

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]

2 番目の実装:

 # 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

を始め、式の結果に名前を付ける可能性を与える代入式 (PEP 572) ( operator)Python 3.8の導入により、リスト内包表記を使用してスキャン左操作を複製できます。:=

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 に答える