'Specify the consecutive values (zeros) and remove them but only if they are consecutive
I have this list of values:
A = [0,0,1,2,3,4,5,6,0,6,6,8,8,0,0,2,3,4,5,12,45,-0,-0,-9,-2,3,-0,-2,-2,-2]
I want to get this list of values for the output :
A = [1,2,3,4,5,6,0,6,6,8,8,2,3,4,5,12,45,-9,-2,3,-0,-2,-2,-2]
Basically, I want to drop the consecutive zeros only, and keep all the other values.
Do you have any idea on how i can do that ? I tried this one but i know there will be in index error :
X = []
for j in range(len(A)):
if A[j] != 0 and A[j+1] != 0:
X.append(A[j])
else:
print('lol')
print(X)```
Solution 1:[1]
You can use itertools.groupby and itertools.chain:
from itertools import groupby, chain
out = list(chain.from_iterable(G for k,g in groupby(A)
if len(G:=list(g))<2 or k!=0))
Explanation:
groupby will group the consecutive values. For each group, if the length is no more than 1 or the key (=value) is not 0, keep it. Finally chain all the groups together and convert to list.
Note that groupby returns iterators so I am using an assignment expression to perform the conversion.
output:
[1, 2, 3, 4, 5, 6, 0, 6, 6, 8, 8, 2, 3, 4, 5, 12, 45, -9, -2, 3, 0, -2, -2, -2]
Solution 2:[2]
With itertools:
from itertools import groupby
X = [x
for x, [*xs] in groupby(A)
if x or len(xs) == 1
for x in xs]
Alternatively:
X = []
for x, [*xs] in groupby(A):
if x or len(xs) == 1:
X += xs
Or taking any x that's not zero or where the previous and next values are not zero (padding with 1):
X = [x
for p, x, n in zip([1]+A, A, A[1:]+[1])
if x or p and n]
Solution 3:[3]
if u dont want to import itertools and prefer list comprehension
A = [i for index,i in enumerate(A) if i!=0 or index not in [0,len(A)] and A[index-1]!=i and A[index+1]!=i ]
note that this expressions uses the precedence of and operator over or operator
enumerate is used too
Solution 4:[4]
Here's a more simple, easy, and bit lengthy than other answers method to solve your problem
A = [0,0,1,2,3,4,5,6,0,6,6,8,8,0,0,2,3,4,5,12,45,-0,-0,-9,-2,3,-0,-2,-2,-2]
ind=[i for i,j in enumerate(A) if j==0]
C=[(ind[i],ind[i+1]) for i in range(len(ind)-1) if ind[i]+1==ind[i+1]]
D=[i for i1 in C for i in i1]
E=["" if i in D else j for i,j in enumerate(A)]
F=[i for i in E if i!=""]
# TEST
d_output=[1,2,3,4,5,6,0,6,6,8,8,2,3,4,5,12,45,-9,-2,3,-0,-2,-2,-2]
print(F==d_output)
Output: 1 i.e Your desired output
If you want to specify the value, then you can wrap it up in a function as below:
def remove_c(list_2,val):
ind=[i for i,j in enumerate(list_2) if j==val]
C=[(ind[i],ind[i+1]) for i in range(len(ind)-1) if ind[i]+1==ind[i+1]]
D=[i for i1 in C for i in i1]
E=["" if i in D else j for i,j in enumerate(A)]
return [i for i in E if i!=""]
print(remove_c(A,10))
Explantion:
- I have taken all the indexes of 0 in the list.
- Checked if the indexes are consecutive or not. If they are, then append them in the list
Cin tuple. - And, because the list
Ccontains tuple, created a flat listDout of listC. - Replaced the indexes of list
Dwith "". - Removed "" for the list. I have noticed a silly mistake in your code:
X = []
for j in range(len(A)): # Mistake here
if A[j] != 0 and A[j+1] != 0: # if we bypassed the above error we can also get error here
X.append(A[j])
else:
print('lol')
print(X)
The problem is when the i is at last index of the list, there would be no other index but you have hard-coded to search for index+1, so it would throw an error.
There are 2 method to solve this:
- Use
tryandexcept. - Replace
range(len(A)torange(len(A)-1).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | mozway |
| Solution 2 | |
| Solution 3 | |
| Solution 4 |
