remove elements of one list from another list python

Question:

Is there a pythonic way to remove elements from one list to another list? (Not removing all duplicates)

For example, given [1, 2, 2, 3, 3, 3] (original list) and [1, 2, 3] (elements to be removed). It will return [2, 3, 3]
We can assume that the two given lists are always valid. Elements in the "to be removed" list will be in the original list.

Thanks!

Asked By: jds

||

Answers:

I would use a counter of the elements to be removed.

So, something like

from collections import Counter 

data = [1, 2, 2, 3, 3, 3]
to_be_removed = [1, 2, 3, 3] # notice the extra 3

counts = Counter(to_be_removed)

new_data = []
for x in data:
    if counts[x]:
        counts[x] -= 1
    else:
        new_data.append(x)

print(new_data)

This solution is linear time / space. If you actually need to modify the list (which is code-smell, IMO), you would require quadratic time

Note, consider if you actually just want a multiset – i.e. you could just be working with counters all along, consider:

>>> Counter(data) - Counter(to_be_removed)
Counter({2: 1, 3: 1})
Answered By: juanpa.arrivillaga

This shoud work


original  = [1, 2, 2, 3, 3, 3] 
remove = [1, 2, 3] 

for i, x in enumerate(original):
    if x in remove:
        original.pop(i)

print(original)
Answered By: Juan Pablo Pisano

I don’t know what problem are you solving with this operation so not sure if this is applicable, but if you can take the elements you want to remove from the original list (for example get random subsequence from the original list and then subtract it) then pythonic and more efficient way (if you do a lot of this operation) would be to use list of hashable objects instead of a list of integers. That way you can do simply set1 – set2 to achieve the goal:

# Create your own element class
class MyElement:
    def __init__(self, value):
        self.value = value

    def __repr__(self):
        return str(self.value)

    # support for less than operator needed for sorting
    def __lt__(self, other):
        return self.value < other.value


original_list = [1, 2, 2, 3, 3, 3]

# Transform list of integers to list of my own MyElement objects
original_list = [MyElement(element) for element in original_list]

# Create subsequence of the original list
to_be_removed = original_list[1:4]

print(original_list)  # [1, 2, 2, 3, 3, 3]
print(to_be_removed)  # [2, 2, 3]

# Subtract the sets
result = set(original_list) - set(to_be_removed)

# Print sorted result
print(sorted(result))  # [1, 3, 3]

It won’t preserve original order! But you can sort it at the end.

Answered By: Jan Lněnička
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.