What is the Pythonic way to remove duplicate duplicates in a list, but allow triplets / more?

I have a list in Python

list1 = [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1] 

There are "groups" of consecutive 1 and 0. For my purposes, I am only interested in consecutive 1. Let’s say if there is a single 1, for example.

  ... 0, 0, 1, 0, 0 ... 

I would like it to be replaced by 0. Similarly, if there are only pairs of 1, they should also become 0s. eg

 .... 0, 0, 1, 1, 0, 0... 

should become

 .... 0, 0, 0, 0, 0, 0... 

But "triplets" of sequential or higher are fine.

I thought that tracking counts 1 with a dictionary, but this is too complicated. The idea would be to iterate over the list, keeping track of the number of consecutive 1s in the list. But how do you “come back” and switch 1s to 0s?

 counter_list = [] for i in list1: if i == 1: counter_list = counter_list + 1 if len(counter_list)==1 or len(counter_list)==2: # now I don't know how to "go back" to change these elements into 0s 
+5
source share
5 answers

itertools.groupby can help by grouping the list into runs 0 or 1. From there, we can use the length of the group from 1s to decide whether to switch it to 0s and use itertools.chain.from_iterable to merge the groups back into one stream:

 import itertools groups = ((key, list(group)) for key, group in itertools.groupby(list1)) fixed_groups = (group if key==0 or len(group)>2 else [0]*len(group) for key, group in groups) result = list(itertools.chain.from_iterable(fixed_groups)) 
+4
source

This is erosion, followed by dilatation, common operations in computer vision:

 >>> from scipy.ndimage.morphology import binary_dilation, binary_erosion >>> print(list1) [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1] >>> print(binary_dilation(binary_erosion(list1)).astype(int)) [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] 

The composition of two operations is called discovery:

 >>> from scipy.ndimage.morphology import binary_opening >>> print(binary_opening(list1).astype(int)) [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] 
+7
source

You can use image processing methods for this. The morphological operation "discovery" with the structural element [1 1 1] should perform this work. There must be a 1 liner.

+6
source

Using a simple for loop. Not sure if this is the most effective way, but it does the trick.

 list1 = [0,0,1,1,0,0,1,0,1,1,1,0,0,1,0,1,1,1] counter_list = [] for i,elem in enumerate(list1): if elem==1: counter_list.append(i) else: if len(counter_list)>0 and len(counter_list)<=2: for e in counter_list: list1[e] = 0 counter_list= [] print(list1) 
0
source

You can turn it into a string and use the regular expression to replace the short runs of '1' with the equivalent runs of '0' , and then return them back to the list:

 >>> import re >>> list1 = [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1] >>> ''.join(map(str, list1)) '0001110011000111111' >>> re.sub(r'(?<!1)1{,2}(?!1)', lambda x: len(x.group())*'0', _) '0001110000000111111' >>> list(map(int, _)) [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] 
-2
source

Source: https://habr.com/ru/post/1266090/


All Articles