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

      

+3


source to share


2 answers


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

+1


source


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.

+1


source







All Articles