1

I'd like to sum up an iterable of integers and yield the growing sum for each element. This is a simple thing using iterative programming:

def growingSum(elements):
  sum = 0
  for element in elements:
    sum += element
    yield sum

But can it be done in a functional way without the use of a variable, so probably as a one-liner using comprehensions?

Charles
  • 50,943
  • 13
  • 104
  • 142
Alfe
  • 56,346
  • 20
  • 107
  • 159
  • `itertools.accumulate()`... but this is a duplicate, I'm afraid. – Martijn Pieters Feb 26 '14 at 10:48
  • possible duplicate of [Cumulative addition whilst looping over a list](http://stackoverflow.com/questions/11879390/cumulative-addition-whilst-looping-over-a-list) – Martijn Pieters Feb 26 '14 at 10:50
  • No, it's more a question about the core language and it's possibilities. By presenting an implementation in the question I think I displayed awareness of the iterative solution which is implemented also in `accumulate()`. This only refers to a library which implements a solution which does not fit my conditions. – Alfe Feb 26 '14 at 10:55

2 Answers2

3

On Python3.2+ you can use itertools.accumulate:

>>> from itertools import accumulate
>>> list(accumulate(range(10)))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • The implementation of `accumulate()` does not fit my conditions, but thanks for that pointer. In case I want to spare me the writing of the five lines in my question, I will use that instead ;-) But my question really was more on an academical level. – Alfe Feb 26 '14 at 10:57
1

Technically, this generator expression works:

((globals().__setitem__('__acc', globals()['__acc'] + x), globals()['__acc'])[1] for x in (globals().__setitem__('__acc', 0), iterable)[1])

(I'm not sure whether this is portable. It might rely on implementation-defined behavior.)

Alternatively, if one local may be introduced:

v = [0]
((v.append(v.pop() + x), v[0])[1] for x in iterable)

In any case, persons caught using such code will be shot. It is a massive hack and an affront to readability and common sense, without the slightest sign of justification or appeal.

  • Wow. Using `setitem()` to make the use of a variable look like a functional approach. That's ugly as hell. ⁺¹ for that. – Alfe Feb 26 '14 at 12:01
  • I just found: `v=[]` followed by `[ len(v.__iadd__(x*[0])) for x in [23,42,78,101] ]`. What do you think? ;-) – Alfe Feb 26 '14 at 12:15
  • @Alfe If introducing a local variable in a separate statement is allowed, I can do much better (will edit). I assumed that's prohibited :-) Your version has the huge disadvantage of essentially counting in unary, i.e. it takes time and memory proportional to the sum, rather than to the number of summands. `sum(v.__iadd__([x])) ...` fixes that, but is still quadratic in the number of summands. –  Feb 26 '14 at 12:22
  • My suggestion was just for fun. But maybe it's a good idea to state the problems with that as well. – Alfe Feb 26 '14 at 13:19
  • Btw, I have no problem with using variables in order to avoid repetition of code; it just should not use it for iteratively summing up the numbers. – Alfe Feb 26 '14 at 13:48