リスト内包表記でこれを行うことができますが、リクエストの特定の条件を考えると、これはジェネレーターの仕事のように思えます。これは、シーケンスとイテレータの両方で機能する非常に一般化されたソリューションです。scanl
オプションの初期値を最後の引数として、渡された iterableに対して Haskell の関数と同等の機能を実行します。
最初の引数は、2 つの引数 (現在の累積状態とシーケンス内の次の項目) を取り、次の累積状態を返す関数でなければなりません。それは同じくらい単純かもしれませんし、operator.add
もっと複雑かもしれません。
>>> def scan(f, seq, init=None):
... seq = iter(seq)
... state = seq.next() if init is None else init
... yield state
... for i in seq:
... state = f(state, i)
... yield state
累積和 (つまり、三角数):
>>> import operator
>>> list(scan(operator.add, range(10)))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
異なる初期値から始める:
>>> list(scan(operator.add, range(1, 10), 10))
[10, 11, 13, 16, 20, 25, 31, 38, 46, 55]
あなたの問題に適用されます:
>>> diffs = [(1, 0), (-1, 1), (1, 3), (1, 3), (-1, 5), (1, 9)]
>>> list(scan(lambda x, y: (x[0] + y[0], y[1]), diffs))
[(1, 0), (0, 1), (1, 3), (2, 3), (1, 5), (2, 9)]
楽しみのためだけに、異なる初期値を使用します。
>>> list(scan(lambda x, y: (x[0] + y[0], y[1]), diffs, (5, -1)))
[(5, -1), (6, 0), (5, 1), (6, 3), (7, 3), (6, 5), (7, 9)]