Suppose I have a list as shown below. How could you iterate over the list and replace the zeros bounded between ones where the length of zeros in between can vary?
Input:
mylist = [0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0]
Output:
mylist = [0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0]
I think you can do this in two phases:
first we obtain the indices where the ones are indicates; and
we take two ones at a time, and fill these all with ones.
Like:
# obtain an iterable of the indices of the ones
ones = iter([i for i,x in enumerate(mylist) if x == 1])
# for every pair of indices
for i0,i1 in zip(ones,ones):
# iterate over the range
for j in range(i0+1,i1):
# and assign 1 to these indices
mylist[j] = 1
This generates:
>>> mylist
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0]
Keep the flag, wherever you're "inside" 1-1 block (and u need to update 0 to 1) or not.
This assumes, that single ("last") 1 will produce ones till the end of the list:
inside = False
for x in range(len(data)):
if data[x]:
inside = not inside
elif inside:
data[x] = 1
[ 0, 1, 0, 1, 0 ] -> [ 0, 1, 1, 1, 0 ]
[ 0, 1, 0, 0, 0 ] -> [ 0, 1, 1, 1, 1 ]
If it was not what you want and last 1 should be ignored:
start_block = None
for x in range(len(data)):
if data[x]:
if start_block is not None:
for y in range(start_block + 1, x):
data[y] = 1
start_block
else:
start_block = x
[ 0, 1, 0, 1, 0 ] -> [ 0, 1, 1, 1, 0 ]
[ 0, 1, 0, 0, 0 ] -> [ 0, 1, 0, 0, 0 ]
Related
I got a list and I want to find the first element index by expression, for example, the list is
list_A = [None, None, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0]
I want to find the index number when the 0 changes to 1 for the first time, which is list_A[8]?
you can do it like this:
>>> list_A = [None, None, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0]
>>> for index, value in enumerate(list_A):
... if index > 0 and list_A[index - 1] == 0 and list_A[index] == 1:
... print(index)
... break
...
8
>>>
you can read about enumerate here
I have an array like
a = np.array( [ 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1] )
and am looking for a way to set consecutive equal elements to zero:
a_desired = np.array( [ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] )
I've had a pretty unsuccessful time of it so far, I've tried something as simple as
for i in range(len(a)-1):
if a[i+1] == a[i]:
a[i+1] = 0
with output [1 0 1 0 0 0 0 1 0 1 0 0 1], as well as adding more conditions, like
for i in range(len(a)-1):
if a[i+1] == a[i]:
a[i+1] = 0
if a[i+1] != a[i] and a[i] == 0 and a[i+1] != a[i]:
a[i+1] = 0
which has output [1 0 0 0 0 0 0 0 0 0 0 0 0], but I can't seem to be able to successfully capture all the conditions required to make this work.
Some help would be appreciated!
I would do it following way:
import numpy as np
a = np.array([1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1])
a[1:][a[:-1]==a[1:]] = 0
print(a)
output:
[1 0 0 0 0 0 0 1 0 0 0 0 1]
I compare a without last element with a without first element, thus I do pair-wise comparison between what might be called previous element and current element, which result in array of Trues and Falses which is 1 shorther then a, then I use it as mask to set 0 where is True. Note that I only modify part of a after first element, as first will never change.
Try numpy xor
np.insert((np.logical_xor(a[:-1], a[1:]) * a[1:]), 0, a[0])
array([1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
Try:
import numpy as np
a = np.array([1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1])
a_desired = np.zeros(a.shape)
for i in range(len(a)-1, -1, -1):
if a[i] == a[i-1] and i != 0:
a_desired[i] = 0
else:
a_desired[i] = a[i]
print(a_desired)
Output:
[1. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 1.]
How about:
value_detected = 0
for i in range(len(a)):
if value_detected:
if a[i] == value_detected:
a[i] = 0
else:
value_detected = a[i]
else:
if a[i]:
value_detected = a[i]
print(a)
For original input, the output:
[1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
Further test, if input is:
a = [ 1, 1, 2, 2, 3, 3, 3, 1, 1, 1, 1, 0, 1]
Then output is:
[1, 0, 2, 0, 3, 0, 0, 1, 0, 0, 0, 0, 1]
From me, first i make copy of original array and then make new desired array like this:
new_a = a.copy()
for i in range(1, len(a)):
if a[i] == a[i-1]: new_a[i] = 0
print(new_a)
Create a list with one element which would be the first element of input list.
Now, just iterate through your list starting from 2nd element and check if it is equal to the previous value.
If yes append 0 else, append the value.
input_arr = [ 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1]
output_arr = [input_arr[0]]
for i in range(1, len(input_arr)):
if input_arr[i]==input_arr[i-1]:
output_arr.append(0)
else:
output_arr.append(input_arr[i])
print (output_arr)
Example:
[0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
In this case I need:
1st '0' group = index: 0-4 , length : 5
1st '1' group = index: 5-6 , length : 2
2nd '0' group = index: 7 , length : 1
2nd '1' group = index: 8-17 , length : 10 <---- NEED THIS the index of max length of '1's
3rd '0' group = index: 18 - 22 , length : 5
I think you are looking for itertools.groupby. With this you can get a list of lists by each grouping of integers in the original dataset.
>>> data = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
>>> [list(group) for _, group in itertools.groupby(data)]
[[0, 0, 0, 0, 0], [1, 1], [0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0,0, 0]]
Or to get indexes, you can also do this in one line using itertools.groupby and .islice and operator.itemgetter
>>> [sorted(set(itemgetter(0, -1)([i[0] for i in g))) for _, g in groupby(enumerate(data), key=itemgetter(1))]
[[0, 4], [5, 6], [7], [8, 17], [18, 22]]
Or to get the starting or ending indexes, use this: (notice min and max determine the start or end index)
>>> [min(i[0] for i in group) for _, group in groupby(data)]
[0, 5, 7, 8, 18]
>>> [max(i[0] for i in group) for _, group in groupby(data)]
[4, 6, 7, 17, 22]
And to get the starting index of the largest group use:
>>> max(([next(group)[0], sum(1 for _ in group)] for _, group in groupby(enumerate(data), key=itemgetter(1))), key=itemgetter(1))[0]
8
The standard library provides itertools.groupby for this purpose. It's a bit tricky to use, because it does a lot of work:
>>> from itertools import groupby
>>> data = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
>>> groupby(data)
<itertools.groupby object at 0x0000015AB6EB3C78>
Hmm. It doesn't seem very useful yet. But we look at the documentation and see that it's a generator, so let's try expanding it into a list:
>>> list(groupby(data))
[(0, <itertools._grouper object at 0x0000015AB6EC2BA8>), (1, <itertools._grouper
object at 0x0000015AB6ED82B0>), (0, <itertools._grouper object at 0x0000015AB6E
D8518>), (1, <itertools._grouper object at 0x0000015AB6EFE780>), (0, <itertools.
_grouper object at 0x0000015AB6F028D0>)]
The 0 and 1 values in here correspond to the 0s and 1s in the original data, but we still have these other objects. Those are also generators:
>>> [(value, list(grouper)) for value, grouper in groupby(data)]
[(0, [0, 0, 0, 0, 0]), (1, [1, 1]), (0, [0]), (1, [1, 1, 1, 1, 1, 1, 1, 1, 1,
1]), (0, [0, 0, 0, 0, 0])]
Now we can see what's going on: the grouper objects generate chunks from the list.
So all we need to do is check the len of those lists and get the maximum value. We fix the comprehension so that we ignore the value and get the len of each grouper, and feed the results to the built-in max instead of making a list:
>>> max(len(list(grouper)) for value, grouper in groupby(data))
10
you can do it another way without itertools:
j=0
for i,val in enumerate(data):
if i == 0:
out=[[val]]
if val == data[i-1]:
out[j] += [val]
else:
j+=1
out += [[val]]
output:
[[0, 0, 0, 0, 0, 0], [1, 1], [0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0]]
now, make a dict with the unique values and the lengths of the sublists for each value:
counts = {}
for o in out:
if o[0] not in counts.keys():
counts[o[0]] = [len(o)]
else:
counts[o[0]] += [len(o)]
output:
{0: [6, 1, 5], 1: [2, 10]}
now get the max length of the sequences with the value you are after, in your case it's 1:
max(counts[1])
output:
10
EDIT : to also get the indices of this specific sequence you can do this:
id0 = 0
for o in out:
if o[0] != 1 or len(o) != max(counts[1]):
id0 += len(o)
if o[0] == 1 and len(o) == max(counts[1]):
id0 -= 1
break
id1 = id0 + max(counts[1]) - 1
print(max(counts[1]), id0, id1)
output:
10 8 17
it isnt the prettiest...but it works :)
You could iterate using the following function:
def count_through_a_list(x):
"""
returns all distinct continuous groups of values in a list
output is in the form of records
"""
# Initialize these values
group_start = 0
group_count = 1
prev = x[0]
groups = []
for i,n in enumerate(x):
# if n is not the same as the previous value OR i is the last index
if n!=prev or i == len(x)-1:
groups.append({'start':group_start, 'end':i-1, 'value':prev, 'length':i-group_start, 'group_counter':group_count})
# Reset the appropriate values
group_count+=1
group_start = i
prev = n
return groups
groups = count_through_a_list(x)
pd.DataFrame(groups, columns=['start','end','value', 'length', 'group_counter'])
start end value length group_counter
0 0 4 0 5 1
1 5 6 1 2 2
2 7 7 0 1 3
3 8 17 1 10 4
4 18 21 0 4 5
I have an array [1,2,3] so I need to fill some blanks or none values between it.
Such as [1,2,3] to [1,0,0,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0]from example I need to insert 5 none values between old member. (the zero number represent to blank or none values.)
So how should I code to do like this ?, some loops with append() or something else.
You can leverage assigning to the slice:
lst = [1,2,3]
newlst = [0] * len(lst) * 6
newlst[::6] = lst
print(newlst)
Prints:
[1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0]
Here's the code:
x = [1,2,3]
y = []
for i in x:
y.append(i)
y.extend([0]*5)
First it appends the element of x itself, then it appends as many 0s as you specify (replace the number 5 with your desired quantity).
Result:
>>> y
[1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0]
This function takes list and number of 0 you want to add in between.
Try this,
>>> def fill_n(arr,n):
temp = []
for el in arr:
temp+=[el]+[0]*n
return temp
Output:
>>> l = [1,2,3]
>>> fill_n(l,5)
[1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0]
What about
l = [1,2,3]
[num if not idx else 0 for num in l for idx in range(6)]
?
I have a random generated list that could look like:
[1, 0, 0, 1, 1, 0, 1, 0, 0, 0]
I need to find all of the distance between the 1's including the ones that wrap around.
For an example the list above, the first 1 has a distance of 3 to the next 1. The second 1 has a distance of 1 to the following 1 and so on.
How do I find the distance for the last 1 in the list using wrap around to the first 1?
def calc_dist(loc_c):
first = []
#lst2 = []
count = 0
for i in range(len(loc_c)):
if loc_c[i] == 0:
count += 1
#lst2.append(0)
elif loc_c[i] == 1:
first.append(i)
count += 1
loc_c[i] = count
#lst2.append(loc_c[i])
#if loc_c[i] + count > len(loc_c):
# x = loc_c[first[0] + 11 % len(loc_c)]
# loc_c[i] = x
count = 0
return loc_c
My expected outcome should be [3, 1, 2, 4].
Store the index of the first 1 you first reference, then when you get to the last 1 you only have to add the index of the first plus the number of 0 elements after the last 1 to get that distance (so len(inputlist) - lastindex + firstindex).
The other distances are the difference between the preceding 1 value and the current index.
from typing import Any, Generator, Iterable
def distances(it: Iterable[Any]) -> Generator[int, None, None]:
"""Produce distances between true values in an iterable.
If the iterable is not endless, the final distance is that of the last
true value to the first as if the sequence of values looped round.
"""
first = prev = None
length = 0
for i, v in enumerate(it):
length += 1
if v:
if first is None:
first = i
else:
yield i - prev
prev = i
if first is not None:
yield length - prev + first
The above generator calculates distances as it loops over the sequence seq, yielding them one by one:
>>> for distance in distances([1, 0, 0, 1, 1, 0, 1, 0, 0, 0]):
... print(distance)
...
3
1
2
4
Just call list() on the generator if you must have list output:
>>> list(distances([1, 0, 0, 1, 1, 0, 1, 0, 0, 0]))
[3, 1, 2, 4]
If there are no 1 values, this results in zero distances yielded:
>>> list(distances([0, 0, 0]))
[]
and 1 1 value gives you 1 distance:
>>> list(distances([1, 0, 0]))
[3]
I've made the solution generic enough to be able to handle any iterable, even if infinite; this means you can use another generator to feed it too. If given an infinite iterable that produces at least some non-zero values, it'll just keep producing distances.
Nice and tidy:
def calc_dist(l):
idx = [i for i, v in enumerate(l) if v]
if not idx: return []
idx.append(len(l)+idx[0])
return [idx[i]-idx[i-1] for i in range(1,len(idx))]
print(calc_dist([1, 0, 0, 1, 1, 0, 1, 0, 0, 0]))
# [3, 1, 2, 4]
print(calc_dist([0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0]))
# [3, 1, 2, 7]
print(calc_dist([0, 0, 0, 0])
# []
You can use numpy:
import numpy as np
L = np.array([1, 0, 0, 1, 1, 0, 1, 0, 0, 0])
id = np.where(test == 1)[0]
# id = array([0, 3, 4, 6], dtype=int64)
res = [id[i]-id[i-1] for i in range(1, len(id))]
# [3, 1, 2]
# Last distance missing:
res.append(len(L)- id[-1])
res = [3, 1, 2, 4]
Note that the information you ask for is comprised above, but maybe the output format is wrong. You were not really specific...
Edit: How to convert list to an array since you generate random list
L = [1, 0, 0, 1, 1, 0, 1, 0, 0, 0]
np.asarray(L)
Edit2: How to check if there is no 1 in the list:
import numpy as np
L = np.array([1, 0, 0, 1, 1, 0, 1, 0, 0, 0])
id = np.where(test == 1)[0]
if len(id) == 0:
res = []
else:
res = [id[i]-id[i-1] for i in range(1, len(id))]
res.append(len(L)- id[-1])
OR:
try:
res = [id[i]-id[i-1] for i in range(1, len(id))]
res.append(len(L)- id[-1])
except:
res = []