I am working with Python3 and trying to create a oneliner that creates a generator that can return the cumulative sum of members of a list.
For example, given the list [1, 2, 3, 4], the generator expression should return 1, 3, 6, 10 in each call to next.
I know how to do this with several lines of code. I would like to find a way to do it as a Python oneliner. The problem I find is how to access the previous values.
You can use:
x = [1, 2, 3, 4]
The following one-liner will return the desired result:
[i for i in itertools.accumulate(x)]
This will return:
[1, 3, 6, 10]
You can do
[sum(lst[:n+1]) for n in range(len(lst))]
but this in inefficient, since every sum is recomputed from scratch. An efficient approach would require an accumulator variable, which is not possible in a comprehension.
Related
With the way that map() is designed it seems like it is intended to be used specifically when you are trying to return modified COPY of a list. I am wondering if there is an alternative to map() that is designed specifically for when you do want to modify the original list rather then returning a modified copy. Here is an example:
def addition(n):
return n + n
numbers = [1, 2, 3, 4]
result = map(addition, numbers)
print(result)
output : [2, 4, 6, 8]
print(numbers)
output : [1, 2, 3, 4]
This is how it would look using map, but what is stored in result is a copy, and not the original list. Is there a python method that modifies the original list items so that if I print(numbers) the original list would be modified?
I've been given a homework task that asks me to find in a list of data the greatest continuous increase. i.e [1,2,3,4,5,3,1,2,3] the greatest static increase here is 4.
I've written a function that takes a single list and spits out a list of sublists like this.
def group_data(lst):
sublist= [[lst[0]]]
for i in range(1, len(lst)):
if lst[i-1] < lst[i]:
sublist[-1].append(lst[i])
else:
sublist.append([lst[i]])
return(sublist)
Which does what it's supposed to
group_data([1,2,3,4,5,6,7,8,9,10,1,2,3,5,4,7,8])
Out[3]: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 5], [4, 7, 8]]
And I now want to subtract the last element of each individual list from the first to find their differences. But I'm having difficulty figuring out how to map the function to each list rather than each element of the list. Any help would be greatly appreciated.
you can do it using map function where arr is your grouped list
list(map(lambda x: x[-1]-x[0], arr ))
For this problem I think itertools.groupby would be a good choice. Since your final goal is to find the difference of longest consecutive numbers:
from itertools import groupby
max_l = max([len(list(g)) - 1 for k, g in groupby(enumerate([1,2,3,4,5,6,7,8,9,10,1,2,3,5,4,7,8]), key=lambda x: x[0] - x[1])])
print(max_l)
#it will print 9
Explanation:
First groupby the numbers with the difference between index and number value. For example [0, 1, 2, 4] will create [0, 0, 0, 1] as the index of 0 is 0, so 0-0=0, for the second one 1-1=0. Then take the maximum length of the grouped list. Since you want difference, I used len(list(g)) - 1
This question already has answers here:
How to find the cumulative sum of numbers in a list?
(25 answers)
Closed 6 years ago.
I have an old list and I want to sum up every single element to a new list:
lst_old = [1, 2, 3, 4, 5]
lst_new = [1, 3, 6, 10, 15]
Is there an elegant way to implement that in Python 3 with short and fast code? Apart from sum() which only prints last element I couldn't find a proper solution for my problem.
You can use itertools.accumulate, eg:
from itertools import accumulate
lst_old = [1, 2, 3, 4, 5]
lst_new = list(accumulate(lst_old))
# [1, 3, 6, 10, 15]
itertools.accumulate as mentioned by Jon Clements is the best way to do. However, in case you want an explicit way to do it, here goes:
lst_old = [1, 2, 3, 4, 5]
sum = 0
lst_new = []
for item in lst_old:
sum += item
lst_new.append(sum)
Main advantage of this is, you can wrap it in a function and if there is any transform or validation need to be performed, can be added.
For example, lets say you want to stop the function keep going after a limit, the following will help:
def accumulate_items(lst_old, limit=0):
sum = 0
output_list = []
for item in lst_old:
sum += item
output_list.append(sum)
if limit and sum > limit:
break
return output_list
The flexibility will be limitless if there is any transformation or operation need to be done here. Have a pre-condition that need to be set? Go ahead. Have a post-condition that need to be tested? Go ahead. Pretty huge list and wanted a generator based solution just like the itertools.accumulate? Go ahead. Need to add a validation or exception handling? Go ahead.
However, no transformation and simply accumulate? The previous answer is the best. Using sum with list indices is pretty slow as the order of complexity sky rockets.
You can take the sum of a slice of a list using listname[start:end], with both start and end as optional arguments (defaulting to the beginning and end of the list):
lst_old = [1, 2, 3, 4, 5]
lst_new = []
for i, num in enumerate(lst_old):
index = i+1
var = sum(lst_old[:index])
print(var)
lst_new.append(var)
In Python I have a list: [11,42,122,1919, 17, 4] and want to calculate its modulo a number (e.g. 10) to give the result as a list: [1,2,2,9,7,4]
Even though it's a homework question, you can do it as:
[a%10 for a in l]
You can also do it without list comprehension, like this:
num_list = [11,42,122,1919, 17, 4]
result = []
for num in num_list:
result.append(num%10)
print(result)
# Output
[1, 2, 2, 9, 7, 4]
If you're new to python then this sort of structure with code is quite common to use.
vals= [1]
for j in xrange(i):
vals.append([k for k in f(vals[j])])
This loop appends values to itself over a loop. If I compress this into a list comprehension, it doesn't work because it doesn't "dynamically" extend vals using itself on each iteration -- it processes vals as it is originally framed.
Is there a way to do a one line list comprehension that dynamically appends like this? Based on my research, it looks like maybe I am looking for a reduce function? (the equivalent of a fold)
You can indeed use reduce for this, using the initial list as the third parameter.
>>> def f(lst):
... return [x+1 for x in lst] + [len(lst)]
>>> reduce(lambda lst, i: lst + [f(lst[i])], range(5), [[1]])
[[1], [2, 1], [3, 2, 2], [4, 3, 3, 3], [5, 4, 4, 4, 4], [6, 5, 5, 5, 5, 5]]
(Note that the initial list should probably be [[1]], not [1], otherwise you are passing a number to f in the first iteration, but a list in all following iterations.)
Also note that concerning performance your original loop is probably a bit faster, as the reduce basically has to create two new lists in each iteration, while you just have to append to a list. Personally, I would go with a variation of the loop, removing the (probably useless) inner list comprehension and using [-1] to make clear that you are always using the previous result.
vals = [[1]]
for _ in xrange(n):
vals.append(f(vals[-1]))