Python Running Sum in List [duplicate] - python

This question already has answers here:
How to find the cumulative sum of numbers in a list?
(25 answers)
Closed 6 years ago.
Given the following list:
a=[1,2,3]
I'd like to generate a new list where each number is the sum of it and the values before it, like this:
result = [1,3,6]
Logic:
1 has no preceding value, so it stays the same.
3 is from the first value (1) added to the value of the second number in the list (2)
6 is from the sum of 1 and 2 from the first two elements, plus the third value of 3.
Thanks in advance!

Python 3 has itertools.accumulate for exactly this purpose:
>>> from itertools import accumulate
>>> a=[1,2,3]
>>> list(accumulate(a))
[1, 3, 6]

If you'd like a numpy solution
from numpy import cumsum
result = list(cumsum(a))

How about an ordinary loop?
a = [1,2,3]
result = []
s = 0
for item in a:
s += item
result.append(s)
print(result)

Python has a function for this.
import itertools
result = list(itertools.accumlate([1, 2, 3]))
Python itertools solve some problems really well you should take some time and read over them.
https://docs.python.org/3/library/itertools.html

try this..
def running_sum(a):
tot = 0
for item in a:
tot += item
yield tot
a = [1,2,3,4]
print list(running_sum(a))

Avinash Raj's code doesn't work correctly.
a = [1,2,3]
b = [sum(a[:(i+1)]) for i, j in enumerate(a)]
print(b)
Edited based on #Avinash Raj

There are about a hundred different ways to do this kind of cumulative sum. Depending on what you actually want to use the result for, a less obvious or less general-purpose solution might be more time- or memory-efficient—although the simple solution below is O(1) in terms of memory and O(N) in time.
The most straightforward procedural approach in virtually every imperative programming language goes something like this:
csum=0
result=[]
for val in a:
csum += val
result.append(csum)
The Python standard library also includes a function to do just this: itertools.accumulate.
import itertools
result = list(itertools.accumulate(a))

Related

Python's list comprehension: Modify list elements if a certain value occurs

How can I do the following in Python's list comprehension?
nums = [1,1,0,1,1]
oFlag = 1
res = []
for x in nums:
if x == 0:
oFlag = 0
res.append(oFlag)
print(res)
# Output: [1,1,0,0,0]
Essentially in this example, zero out the rest of the list once a 0 occurs.
Some context, a list comprehension is a sort of "imperative" syntax for the map and filter functions that exist in many functional programing languages. What you're trying to do is usually referred to as an accumulate, which is a slightly different operation. You can't implement an accumulate in terms of a map and filter except by using side effects. Python allows you have side effects in a list comprehension so it's definitely possible but list comprehensions with side effects are a little wonky. Here's how you could implement this using accumulate:
nums = [1,1,0,1,1]
def accumulator(last, cur):
return 1 if (last == 1 and cur == 1) else 0
list(accumulate(nums, accumulator))
or in one line:
list(accumulate(nums, lambda last, cur: 1 if (last == 1 and cur == 1) else 0))
Of course there are several ways to do this using an external state and a list comprehension with side effects. Here's an example, it's a bit verbose but very explicit about how state is being manipulated:
class MyState:
def __init__(self, initial_state):
self.state = initial_state
def getNext(self, cur):
self.state = accumulator(self.state, cur)
return self.state
mystate = MyState(1)
[mystate.getNext(x) for x in nums]
nums = [1,1,0,1,1]
[int(all(nums[:i+1])) for i in range(len(nums))]
This steps through the list, applying the all operator to the entire sub-list up to that point.
Output:
[1, 1, 0, 0, 0]
Granted, this is O(n^2), but it gets the job done.
Even more effective is simply to find the index of the first 0.
Make a new list made of that many 1s, padded with the appropriate quantity of zeros.
if 0 in nums:
idx = nums.index(0)
new_list = [1] * idx + [0] * (len(nums) - idx)
... or if the original list can contain elements other than 0 and 1, copy the list that far rather than repeating 1s:
new_list = nums[:idx] + [0] * (len(nums) - idx)
I had an answer using list comprehension, but #Prune beat me to it. It was really just a cautionary tail, showing how it would be done while making an argument against that approach.
Here's an alternative approach that might fit your needs:
import itertools
import operator
nums = [1,1,0,1,1]
res = itertools.accumulate(nums, operator.and_)
In this case res is an iterable. If you need a list, then
res = list(itertools.accumulate(nums, operator.and_))
Let's break this down. The accumulate() function can be used to generate a running total, or 'accumulated sums'. If only one argument is passed the default function is addition. Here we pass in operator.and_. The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python. When an accumulated and is run on a list of 0's and 1's the result is a list that has 1's up till the first 0 is found, then all 0's after.
Of course we're not limited to using functions defined in the operator module. You can use any function that accepts 2 parameters of the type of the elements in the first parameter (and probably returns the same type). You can get creative, but here I'll keep it simple and just implement and:
import itertools
nums = [1,1,0,1,1]
res = itertools.accumulate(nums, lambda a, b: a and b)
Note: using operator.and_ probably runs faster. Here we're just providing an example using the lambda syntax.
While a list comprehension is not used, to me it has a similar feel. It fits in one line and isn't too hard to read.
For a list comprehension approach, you could use index with enumerate:
firstIndex = nums.index(0) if 0 in nums else -1
[1 if i < firstIndex else 0 for i, x in enumerate(nums)]
Another approach using numpy:
import numpy as np
print(np.cumprod(np.array(nums) != 0).tolist())
#[1, 1, 0, 0, 0]
Here we take the convert nums to a numpy array and check to see if the values are not equal to 0. We then take the cumulative product of the array, knowing that once a 0 is found we will multiply by 0 from that point forward.
Here is a linear-time solution that doesn't mutate global state, doesn't require any other iterators except the nums, and that does what you want, albeit requiring some auxiliary data-structures, and using a seriously hacky list-comprehension:
>>> nums = [1,1,0,1,1]
>>> [f for f, ns in [(1, nums)] for n in ns for f in [f & (n==1)]]
[1, 1, 0, 0, 0]
Don't use this. Use your original for-loop. It is more readable, and almost certainly faster. Don't strive to put everything in a list-comprehension. Strive to make your code simple, readable, and maintainable, which your code already was, and the above code is not.

Changing from lists to arguments in Python 3.0

I've recently constructed a piece of python code which finds the least commonly repeated number in a list! Here is my code...
from collections import Counter
def least_common():
from collections import Counter
List = [1,1,1,0,0,3,3,2]
CountList = Counter(List)
Mincount = min(CountList.values())
least_common = next(n for n in reversed(List) if CountList[n] == Mincount)
print (least_common)
least_common()
However as you can clearly see, this uses a list to call the numbers which will be compared.
I'm now trying to get it to do the same task, but instead of using a built in list, I want it to use an argument of integers.
For example
def the_least_common(integers)
--------code with argument which will find lowest repeated number---------
print the_least_common([1,1,1,0,0,3,3,2])
LEAST COMMON BEING 2
Is any of the code which I've already created reusable for what I now need to create? Apologies if this is a stupid question or comes across as really simple as I'm a little stuck
Any advice is much appreciated!
Since you're using Counter, there's a builtin method - most_common - that returns a sorted list of elements and their counts, starting with the most common first. You can query the last element of this list.
In [418]: Counter([1,1,1,0,0,3,3,2]).most_common()[-1]
Out[418]: (2, 1)
Your function would look something like this:
def least_common(data):
return Counter(data).most_common()[-1][0]
If your data can have multiple integers with the same least count, and your function needs to return every one of them, you can iterate over most_common:
def least_common(data):
c = Counter(data).most_common()[::-1]
yield c[0][0]
for x, y in c[1:]:
if x != c[0][1]:
break
yield y

How to perform this operation using combined if and for statements

How do we combine a IF statement and FOR loop in python. Like
list = [1,2,3,4]
x = 4
count = 0
for i in list:
if (i == x):
count += 1
How do we combine lines 4, 5, 6 in a single line? Is this possible?
Yeah it can be, what you are trying to do is count the occurences of number and Python List already has a method count() to get the job done. But You should refrain from using the variable name as list it would shadow the Python list data structure.
>>> number_list = [1, 2, 3, 4]
>>> print number_list.count(4)
>>> 1
number_count = sum(1 for i in number_list if i == x)
Do not use list or count as variable names since there could be confusion with the built-in meanings of those names. Terence Hill's answer is good but will use more memory if the list is long, since it builds a full list before finding its size. Mine is a generator expression and never builds the full list. ZdaR's answer is the most pythonic since it uses a built-in feature of Python and will probably be the fastest and use the least memory. This answer sticks the closest to what you actually asked.

index into a circular array

I have a circular array. I created it with the following:
from itertools import cycle
myArray = ['a','b','c','d']
pool = cycle(myArray)
Now I want to print the nth item in pool where n could be larger than 4. Normally this would be a simple use of the modulo function but logically I think Python has a method which will know the number of elements in the pool (4 in this example) and automatically apply the modulo function.
For example the 1st and 5th item is 'a'. So I'm hoping for, logically, the equivalent of pool[0] and pool[4] giving me 'a'.
Is there such a method?
No, there's no built-in method to accomplish what you're attempting to do. As suggested earlier, you could use zip, but that would involve indexing into the result based on your sequence, as well as generating n elements out to the item you want.
Sometimes the simplest approach is the clearest. Use modulo to accomplish what you're after.
def fetch_circular(n):
myArray = ['a','b','c','d']
return myArray[n % 4]
I think you may be confusing arrays with generators.
The modulo function of an array is the way to go, in terms of performance.
cycle is a function which generates elements as they are requested. It is not a Cycle class with convenient methods. You can see the equivalent implementation in the documentation, and you'll probably understand what is the idea behind it:
https://docs.python.org/2/library/itertools.html#itertools.cycle
A list is definitely the way to go but if you actually had a cycle object and wanted the nth object wrapping around, you could islice:
from itertools import cycle, islice
myArray = ['a','b','c','d']
pool = cycle(myArray)
print(next(islice(pool, 5)))
a
Note once you call next(islice you have started cycling the list, if you actually want to be constantly rotating you may actually want a deque
Your pool object is already a generator and it will keep looping through myArray forever, so all you need is to zip your iterator with pool this way:
>>> pool = cycle(myA)
>>> for i,item in zip(range(10),pool):
print i,item
0 a
1 b
2 c
3 d
4 a
5 b
6 c
7 d
8 a
9 b
>>>

How to tell if items occur sequentially in a list in python

I am trying to figure out how to more cleanly determine if a particular item occurs in my list sequentially
for example suppose I have a list:
my_list=[1,2,2,2,4,5,1,0]
in the above example repeated instances of 1 do not occur sequentially in the list but all instances of 2 do. The only way I can seem to figure out how to do this is very clumsy
def check_sequencing(some_list,item_to_check):
prev_instance = 0
difference_list = []
for counter, item in enumerate(some_list):
if item_to_check == item:
difference_list.append(counter - prev_instance)
prev_instance = counter
if set(difference_list[1:]) == set([1]):
return 'True'
else:
return 'False'
I am trying to avoid importing another library (numpy) I was just sure when I started down this road that their would be a one liner but I can't find it.
>>> collections.Counter(x[0] for x in itertools.groupby(my_list)).get(1, 0) > 1
True
>>> collections.Counter(x[0] for x in itertools.groupby(my_list)).get(2, 0) > 1
False
You can use itertools.groupby to do this:
>>> import itertools
>>> any(len(list(n[1])) >= 2 for n in itertools.groupby(l))
True
If you want to avoid using len(list(gen)), you could use something like this:
>>> import itertools
>>> any(sum(1 for i in n[1]) >= 2 for n in itertools.groupby(l))
True
Ok, this time i have a real one-liner that works:
all(x==i for x in L[L.index(i):len(L)-[k for k in reversed(L)].index(i)])
If it's true, then it occurs more than once. Replace L with your list and i with the term you're searching for.

Categories

Resources