I want to get a running total from a list of numbers.
For demo purposes, I start with a sequential list of numbers using range
a = range
This can be implemented in 2 lines in Python.
Using a default parameter eliminates the need to maintain an aux variable outside, and then we just do a map
to the list.
def accumulate(x, l=[0]): l[0] += x; return l[0];
map(accumulate, range(20))
I wanted to do the same thing to generate cumulative frequencies that I could use bisect_left over - this is the way I've generated the list;
[ sum( a[:x] ) for x in range( 1, len(a)+1 ) ]
Another one-liner, in linear time and space.
def runningSum(a):
return reduce(lambda l, x: l.append(l[-1]+x) or l if l else [x], a, None)
I'm stressing linear space here, because most of the one-liners I saw in the other proposed answers --- those based on the pattern list + [sum]
or using chain
iterators --- generate O(n) lists or generators and stress the garbage collector so much that they perform very poorly, in comparison to this.
This is inefficient as it does it every time from beginning but possible it is:
a = range(20)
runtot=[sum(a[:i+1]) for i,item in enumerate(a)]
for line in zip(a,runtot):
print line
Here's a linear time solution one liner:
list(reduce(lambda (c,s), a: (chain(c,[s+a]), s+a), l,(iter([]),0))[0])
Example:
l = range(10)
list(reduce(lambda (c,s), a: (chain(c,[s+a]), s+a), l,(iter([]),0))[0])
>>> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
In short, the reduce goes over the list accumulating sum and constructing an list. The final x[0]
returns the list, x[1]
would be the running total value.
If you can use numpy, it has a built-in function named cumsum
that does this.
import numpy
tot = numpy.cumsum(a) # returns a numpy.ndarray
tot = list(tot) # if you prefer a list