Reputation: 61
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!
Upvotes: 0
Views: 1305
Reputation: 11
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.
Upvotes: 0
Reputation: 127
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)
Upvotes: -1
Reputation: 95873
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})
Upvotes: 3