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(20)
runningTotal = []
for n in range(len(a)):
new = runningTotal[n-1] + a[n] if n > 0 else a[n]
runningTotal.append(new)
# This one is a syntax error
# runningTotal = [a[n] for n in range(len(a)) if n == 0 else runningTotal[n-1] + a[n]]
for i in zip(a, runningTotal):
print "{0:>3}{1:>5}".format(*i)
yields
0 0
1 1
2 3
3 6
4 10
5 15
6 21
7 28
8 36
9 45
10 55
11 66
12 78
13 91
14 105
15 120
16 136
17 153
18 171
19 190
As you can see, I initialize an empty list []
, then append()
in each loop iteration. Is there a more elegant way to this, like a list comprehension?
If you can use numpy, it has a built-in function named
cumsum
that does this.Here's a linear time solution one liner:
Example:
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.You are looking for two things: fold (reduce) and a funny function that keeps a list of the results of another function, which I have called running. I made versions both with and without an initial parameter; either way these need to go to reduce with an initial [].
These will take a long time on really large lists due to the + operator. In a functional language, if done correctly, this list construction would be O(n).
Here are the first few lines of output:
This is inefficient as it does it every time from beginning but possible it is:
If you are using Python3.x and up, the module
itertools
has a function calledaccumulate()
which will do the trick.Here is an example:
A list comprehension has no good (clean, portable) way to refer to the very list it's building. One good and elegant approach might be to do the job in a generator:
to get this as a list instead, of course, use
list(running_sum(a))
.