0

lets assume we have the following list

lst = [3,6,1,4]

I want to be able to get the following result from this list

result = [4, 10, 11, 15]

the pattern for the calculation is given below:

1 + 3 = 4

1 + 3 + 6 = 10

1 + 3 + 6 + 1 = 11

1 + 3 + 6 + 1 + 4 = 15

in other words the result is 1 plus the cumulative sum of the input array.

How can one define a function that can solve this problem?

ClimateUnboxed
  • 7,106
  • 3
  • 41
  • 86
Kristof Pal
  • 966
  • 4
  • 12
  • 28
  • What's the pattern here? I could say it's a piecewise function and you can hardcode the answers in based on what you're showing me. – 2rs2ts Feb 11 '14 at 23:59
  • 1
    I'm assuming you've made a simple mistake and the resultant list should be `[4,10,11,15]`, but if I've misunderstood the pattern please let me know so I can correct my answer – Adam Smith Feb 12 '14 at 00:04
  • At this point I'd like to see a tail-recursive, memoized recursive solution to this problem now. – 2rs2ts Feb 12 '14 at 00:16
  • @2rs2ts why? would that be more efficient than a simple generator function? – M4rtini Feb 12 '14 at 00:17
  • @M4rtini nah, I'm just curious to see it. I had a simple naive implementation but couldn't think of a robust one. – 2rs2ts Feb 12 '14 at 14:43
  • Possible duplicate of [How to find the cumulative sum of numbers in a list?](https://stackoverflow.com/questions/15889131/how-to-find-the-cumulative-sum-of-numbers-in-a-list) – ClimateUnboxed Aug 27 '19 at 07:28

5 Answers5

5
[sum(lst[:i+1])+1 for i in range(len(lst))]

Each element of the final list is the sum of one more successive element of the original list, right? List comprehensions are good at building lists from iterables :)

Here's what we're doing, and here's the docs on list comps:

[sum(lst[:i+1])+1 for i in range(len(lst))]
 ^^^^^^^^^^^^^^^^
# This element is the sum+1 of the slice starting at lst[0] and ending at i,

[sum(lst[:i+1])+1 for i in range(len(lst))]
                  ^^^^^^^^^^^^^^^^^^^^^^^^
# Do this for one element each for every i in range(len(lst))

[sum(lst[:i+1])+1 for i in range(len(lst))]
^                                         ^
# And give me the results as a list.

Note that you can also do generator expressions using the same format but enclosing them with () instead of [], and you can make dictionary comprehensions using {key:value for key,value in iterable}

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • 1
    Was going to correct you, but you already got it. (I think. Still not sure about what OP is asking.) – 2rs2ts Feb 12 '14 at 00:01
  • 2
    @adsmith Id just like to add, that although this is fairly readable code, it is also quite inefficient, since you're computing the sum of every sublist there. – M4rtini Feb 12 '14 at 00:32
  • @adsmith for the first case, where you have written "# This element is the sum+1 of the slice starting at lst[0] and ending at i"; shouldn't it be "ending at i+1" or am I wrong? – Kristof Pal Feb 12 '14 at 00:56
  • @WolfgangKuehne since the slice notation is exclusive, but I wouldn't generally think of "starting at x and ending at y" as being exclusive (wouldn't "start at 1 and end at 2" be [1,2]?), no. `"abcd"[0:1] == "a"` – Adam Smith Feb 12 '14 at 01:36
3

if the pattern is the cumulative sum + 1 this should do it. Using a basic generator and the solution is fairly easy and efficient.

def csum(mylist, c=1):
    total = c
    for i in mylist:
        total += i
        yield total 

lst = [3,6,1,4]

print list(csum(lst))

output : [4, 10, 11, 15]

M4rtini
  • 13,186
  • 4
  • 35
  • 42
  • 1
    I'd recommend you not use `l` as a variable name. I thought it was a `1` and had no idea how `for i in 1` didn't immediately strike you as an error! :). As an aside, I feel like I need to spend two weeks learning about generators every time I see a function with `yield` :) – Adam Smith Feb 12 '14 at 00:11
  • 1
    @adsmith yeah i should, bad habit of using short variable names is hard to break.. In this case the generator use is perfect, since we get easy to read and efficient code. – M4rtini Feb 12 '14 at 00:15
  • 1
    I have the opposite problem. There's only so many times I can type expressions like: `longest_string_in_iterable = max(len(this_string), len(longest_string_in_iterable))` before I start questioning my sanity. – Adam Smith Feb 12 '14 at 00:17
  • 1
    you would lose that habit fairly quickly if you had to work any prolonged time with arcgis\arcpy. Where it will simply crap out on you if you use to long names for stuff. And off course without any sensible error messages :D – M4rtini Feb 12 '14 at 00:22
2

This might be a little easier to understand than a list comprehension:

result = []
total = 1 
lst = [3,6,1,4]

for value in lst:
     total += value
     result.append(total)

print result
agconti
  • 17,780
  • 15
  • 80
  • 114
0

This isn't useful in your specific case, because you want to add 1 to everything, but you can use your original list:

In [1]: lst = [3,6,1,4]

In [2]: from itertools import accumulate

In [3]: list(accumulate(lst))
Out[3]: [3, 9, 10, 14]

or you can just add 1 to the beginning of your list and then chop it off

In [1]: lst = [1,3,6,1,4]

In [2]: from itertools import accumulate

In [3]: list(accumulate(lst))
Out[3]: [1, 4, 10, 11, 15]

In [4]: list(accumulate(lst))[1:]
Out[4]: [4, 10, 11, 15]

edit: Just checked, this doesn't work for 2.7, sorry about that. I'll leave it here in case anyone else finds it useful.

Garth5689
  • 622
  • 4
  • 15
0

you can also use the numpy cumsum function

 import numpy as np
 lst=[3,6,1,4]
 result=np.cumsum(lst)+1

if you want the result as a list instead of a np array:

 result=list(np.cumsum(lst)+1)

 result
 [4, 10, 11, 15]
ClimateUnboxed
  • 7,106
  • 3
  • 41
  • 86