Remove all instances between duplicate items in a list, Python
I need to write a function that takes a list, and removes all elements from that list that are between two identical elements (and keep one of the same elements).
eg.
list1 = ['a', 'b', 1, 'c', 'd', 'e', 'f', 'g', 'h', 1, 'i', 'j']
list2 = ['a', 'b', 1, 'c', '2', 'd', '2', 'e', 'f', 1, 'g', 'h']
list3 = ['a', 1, 'b', 'c', 1, 'd', 2, 'e', 'f', 2, 'g']
print(funct(list1))
print(funct(list2))
print(funct(list3))
will result in:
['a', 'b', 1, 'i', 'j']
['a', 'b', 1, 'g', 'h']
['a', 1, 'd', 2, 'g']
It can be assumed that it will always be the case that any second instance of repeat blocks in the list will always be completely split or completely inside another block.
eg.
['a', 1, 'b', 2, 'c', 2, 'd', 1, 'e']
or
['a', 1, 'b', 1, 'c', 2, 'd', 2, 'e']
but never
['a', 1, 'b', 2, 'c', 1, 'd', 2, 'e']
I wrote some code to do this, but you don't like the need to create a separate list and add items to that list, and rather just remove the items from the original list.
This is what I have, any help would be greatly appreciated :)
def funct(list):
unlooped = []
appending = True
list_index = 1
for item in list:
if appending:
unlooped.append(item)
elif item == looper:
appending = True
if item in list[list_index:] and appending:
appending = False
looper = item
list_index += 1
return unlooped
source to share
how about this:
def unloop(ls):
return [x for i,x in enumerate(ls) if not set(ls[:i]).intersection(set(ls[i:]))]
Explanation: take item x
at position i
from ls
if intersection of elements [0..i-1]
and is [i..n]
empty, i.e. the element does not appear before or after x
.
it works for the 3 examples you gave, might need to test it for edge cases
source to share
You wrote, "I wrote code to do this, but you don't like the need to create a separate list and add items to that list, and rather just remove the items from the original list." I assumed it meant removing items from the original list, so I wrote a solution that removes whole chunks from the list. Using a list comprehension is another way to create another list and add items to it, so I would like to avoid this approach.
def unloop(lst):
for i, v in enumerate(lst):
try:
j = lst.index(v, i+1)
lst[i:j] = []
except ValueError:
pass
return lst
I think there are ways to make this algorithm more efficient. I'll think about it. As a side note, it's good to get in the habit of avoiding name collisions with built-in objects. For example, if you have a variable named list
, it will be difficult for you to use the built-in name list
to convert other iterations to lists.
source to share