I have the following array
a = [0,0,1,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1]
I want to group every 3rd element and sum all of the elements within each group. So I can get a new array with a new size showing this sum
b = [1,0,2,0,3,0,1]
Any suggestions?
Simply, most pythonicly would be the following
b = [sum(a[i:i+3]) for i in range(0, len(a), 3)]
where your input array is a.
>>> a = [0,0,1,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1]
>>> b = [sum(a[i:i+3]) for i in range(0, len(a), 3)]
>>> b
[1, 0, 2, 0, 3, 0, 1]
You can split in chunk and sum:
step = 3
[sum(a[i:i+step]) for i in range(0, len(a),step)]
[1, 0, 2, 0, 3, 0, 1]
If the length is not the multiple of step, last chunk might be smaller.
Maybe something like this:
a = [0,0,1,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1]
b = []
for i in range(0,len(a),3):
b.append(sum(a[i:i+3]))
print b
Output:
[1, 0, 2, 0, 3, 0, 1]
Another option using groupby from itertools:
from itertools import groupby
[sum(v for _, v in g) for _, g in groupby(enumerate(a), key = lambda x: x[0]/3)]
# [1, 0, 2, 0, 3, 0, 1]
Or another way to use zip:
[sum(v) for v in zip(a[::3], a[1::3], a[2::3])]
# [1, 0, 2, 0, 3, 0, 1]
Related
Input
l = [0, 0, 1, 2, 3]
I want to add 1 to index range from 2 to 3
so output should be
l = [0, 0, 2, 3, 3]
l[2:3] = l[2:3] + 1
The easiest way would be to use numpy, it's quite optimized and uses C/C++ loops under the hood, so it's blazingly fast:
>>> import numpy as np
>>> a = [0, 0, 1, 2, 3]
>>> b = np.array(a)
>>> b[2:4] += 1
>>> b
array([0, 0, 2, 3, 3])
>>>
You can try this:
for i in range(2, 4):
l[i] += 1
A possible solution can make use of list-comprehension:
l[2:4] = [x+1 for x in l[2:4]]
For a hilariously overblown solution:
from operator import add
l = [0, 0, 1, 2, 3]
deltas = [0, 0, 1, 1, 1]
result = list(map(add, l, deltas))
note that this does not modify l, but creates a new list in result
I need to manipulate list to get subtraction (subtracting each number from every number on its right).
I have tried using below code which is working with 2 for loops, is there anyway I can do it in only 1 for loop or in a better way then I did.
list=[3,2,5,4,3]
output_list = [0]
for element in list:
for i in range(0, length(list)):
new_element = [ (list[i] - element) if i > index(element) else 0]
if new_element > 0:
output_list.append( new_element )
example:
input [3,2,5,4,3]
subtract like [2-3, 5-3, 4-3, 3-3, 5-2, 4-2, 3-2, 4-5, 3-5, 3-4] = [-1, 2, 1, 0, 3, 2, 1, -1, -2, 1]
output with values > 0, first 0 is from initialization [0, 2, 1, 3, 2, 1, 1]
This should generate the correct output:
values = [3,2,5,4,3]
print([j-i for k,i in enumerate(values[:-1]) for j in values[k+1:] if j-i > 0])
Try this, you can use itertools.combinations
>>> from itertools import combinations
>>> from operator import sub
>>> l = [3,2,5,4,3]
>>> [0]+[sub(c[1],c[0]) for c in combinations(l,2) if sub(c[1],c[0]) > 0]
[0, 2, 1, 3, 2, 1]
using list comprehension
a=[3,2,5,4,3]
b= [j-a[i] for i,v in enumerate(a) for j in a[i+1:] if j-a[i]>0]
print(b)
output
[2, 1, 3, 2, 1]
I have a long list (several hundred thousand items) of numbers and I want to create a new list of equal size to find out the places where there are consecutive repetitions of numbers. The new list will have 0 and 1 values, such that for consecutive repeated indexes the new list will have 1 and for remaining indexes it will have 0 value.
If there is something as a pandas column that can be helpful as well.
Sample given list and resultant array. List can have float values also.
given_array = [1, 2, 3, 5, 5, 5, 5, 0, -2, -4, -6, -8, 9, 9, 9]
result_array = [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
I have given a small working example of my code below.
import itertools
def list_from_count(list_item):
"""
Function takes an iterator and based on the length of the item
returns 1 if length is 1 or list of 0 for length greater than 1
"""
if len(list(list_item[1])) == 1:
return 1
else:
return [0] * len(list(list_item[1]))
r0 = list(range(1,4))
r1 = [5]*4
r2 = list(range(0,-10,-2))
r3 = [9]*3
r = r0 + r1 + r2 + r3
gri = itertools.groupby(r)
res = list(map(list_from_count,gri))
print ("Result",'\n',res)
Result
[1, 1, 1, [], 1, 1, 1, 1, 1, []]
Thanks in advance!
You can use itertools.groupby and output repeated 1s if the length of a group is greater than 1:
from itertools import groupby
result_array = []
for _, g in groupby(given_array):
size = sum(1 for i in g)
if size == 1:
result_array.append(0)
else:
result_array.extend([1] * size)
or with a list comprehension:
result_array = [i for _, g in groupby(given_array) for s in (sum(1 for i in g),) for i in ([0] if s == 1 else [1] * s)]
result_array becomes:
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
You're using len(list(list_item[1])) twice. The first time you use it, it processes all the items in the iterator. When you call it the second time, the iterator is all used up, so it returns 0, that's why you get a zero-element list.
You need to save the length in a variable the first time:
def list_from_count(list_item):
l = len(list(list_item[1]))
if l == 1:
return [0]
else:
return [1] * l
You also need to return a list consistently from this function, then you can concatenate all the results, so you don't get a mix of numbers and sublists.
res = []
for el in gri:
res += list_from_count(el)
print(res)
This situation is more akin to a run length encoding problem. Consider more_itertools.run_length:
Given
import more_itertools as mit
iterable = [1, 2, 3, 5, 5, 5, 5, 0, -2, -3, -6, -8, 9, 9, 9]
Code
result = [[0] if n == 1 else [1] * n for _, n in mit.run_length.encode(iterable)]
result
# [[0], [0], [0], [1, 1, 1, 1], [0], [0], [0], [0], [0], [1, 1, 1]]
Now simply flatten the sub-lists (however you wish) into one list:
list(mit.flatten(result))
# [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
Details
mit.run_length.encode compresses an iterable by yielding tuples of (value, # of repititions), e.g.:
list(mit.run_length.encode("abaabbba"))
# [('a', 1), ('b', 1), ('a', 2), ('b', 3), ('a', 1)]
Our comprehension ignores the value, uses repetitions n and creates sub-lists of [0] and [1] * n.
Note: more_itertools is a third-party package. Install via > pip install more_itertools.
Use the PANDAS shift operator to create a vector shifted 1 element. Compare that to the original. This will give you a vector of True/False values, showing where an element matched the previous one. Run a linear search down that list to extend one element at the front: change [False, True] to [True, True]. Convert to int, and you have the list you specified.
Having a bit of writing out the code.
For example, if I have an array of:
a = ([0, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 0], [1, 0, 1, 3], [0, 1, 1, 3])
if I want to add first element of each item,
as in to return a list of 0 + 0 + 0 + 1 + 0, 0 + 1 + 0, 0 + 0 ...
I wrote the code:
def test(lst):
sum = 0
test_lst = []
i = 0
while i in range(0, 4):
for j in range(0, len(lst)):
sum += lst[j][i]
test_lst.append(sum)
i += 1
return test_lst
I get index size error.
How can I go about this?
sum(zip(*a)[0])
zip is a function that takes any number of n-length sequences and returns n tuples (among other things). The first of these tuples has the elements that came first in the tuples passed to zip. sum adds them together.
EDIT:
In Python 3, the above doesn't work. Use:
sum(next(zip(*a)))
instead. For all such sums,
map(sum, zip(*a))
a = ([0, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 0], [1, 0, 1, 3], [0, 1, 1, 3])
Try using list comprehensions:
sum([item[0] for item in a])
The line above takes the first element of each list in the tuple, then puts it into a temporary list. We then call sum on that temporary list, which yields the answer.
This question already has answers here:
python: most elegant way to intersperse a list with an element
(15 answers)
Closed 6 years ago.
I have a list like
[1, 2, 3, 4, 5]
and I want to add zeroes at odd indexes:
[1, 0, 2, 0, 3, 0, 4, 0, 5]
My first thought was to create a list with zeroes and replace them with the values from the original list.
listOfZeros = [0] * (2*len(list)-1)
j = 0
for i in range(0, len(listOfZeros)):
if (i%2 == 0):
listOfZeros[i] = h_temp[j]
j += 1
This actually works, but I do dislike for loops and adding another counter j. Isn't there a better way by using slicing?
You can use insert(). Looking at your output, assuming you are not counting index 0 as even.
a = [1,2,3,4,5]
for x in range(len(a)):
a.insert(2*x+1, 0)
one way is by using zip:
a = [1, 2, 3, 4, 5]
d = [x for t in zip (a, [0] * len(a)) for x in t][:-1]
When you use zip, you create list of tuples.
a = [1,2,3,4,5]
b = [0,0,0,0,0]
c = zip(a,b)
#zip (a,b) creates [(1,0),(2,0),(3,0),(4,0),(5,0)]
Then you loop over the set of tuples to arrange them into list:
d = [x for t in c for x in t] #creates [1,0,2,0,3,0,4,0,5,0]
and cut the last element (since you end with 5)
[x for t in c for x in t][:-1] #take out the last 0
#resulting in [1,0,2,0,3,0,4,0,5]
then you are done.
You can do it with a generator:
def zero_on_odd(mylist):
for i in mylist:
yield i
yield 0
a = [1, 2, 3]
with_zeros = list(zero_on_odd(a))[:-1]
If you want to go functional...
from itertools import chain, repeat
_list = [1,2,3,4,5]
list(chain(*zip(_list, repeat(0))))[:-1]
# [1, 0, 2, 0, 3, 0, 4, 0, 5]
If you want to be silly...
[int(i) for i in '0'.join(str(i) for i in _list)]
# still [1, 0, 2, 0, 3, 0, 4, 0, 5]
Or, if you want to be functional AND silly...
map(int, '0'.join(map(str, _list)))
# really, it's still [1, 0, 2, 0, 3, 0, 4, 0, 5]
# except in Python 3.X, there it's a map object...
But, you should probably opt for one of the custom generator solutions.
For the fun of it, here is an itertools solution:
from itertools import islice, chain
data = [1,2,3,4,5]
print list(islice(chain.from_iterable((x, 0) for x in data), 0, 2 * len(data)-1))
Giving:
[1, 0, 2, 0, 3, 0, 4, 0, 5]
Another zip way:
>>> li
[1, 2, 3, 4, 5]
>>> [e for t in zip(li,[0]*(len(li)-1)) for e in t]+[li[-1]]
[1, 0, 2, 0, 3, 0, 4, 0, 5]
You can also use range and slice assignment:
>>> li=[1,2,3,4,5]
>>> for i in range(1,len(li)+len(li)-1, 2): li[i:i]=[0]
...
>>> li
[1, 0, 2, 0, 3, 0, 4, 0, 5]
And, a list comprehension:
>>> [li[i/2] if not i%2 else 0 for i in range(len(li)*2-1)]
[1, 0, 2, 0, 3, 0, 4, 0, 5]
A hacky way:
>>> ls1 = [1, 2, 3, 4, 5]
>>> ls2 = []
>>> list(ls2.extend([n, 0]) for n in ls1)
[None, None, None, None, None]
>>> ls2
[1, 0, 2, 0, 3, 0, 4, 0, 5, 0]