Reputation: 396
I'm aware variations of this question have been asked already, but none of the ones I've been able to find have addressed my specific aim.
I am trying to take two lists in Python with string elements and remove the overlapping sections of the two. For example:
list1 = ["25","+","7","*","6","/","7"]
list2 = ["7","*","6"]
Should go to
["25","+","/","7"]
I've considered a list comprehension along the lines of
[i for i in list1 if not in list2]
but this would yield
["25","+","/"]
as both instances of "7" would be taken out.
How can I achieve what I'm trying to do here? Thanks.
Edit - this was marked as a possible duplicate. In my example with the list comprehension, I already explained how it is a different problem to the one linked.
Upvotes: 2
Views: 2977
Reputation: 7994
Using remove
method. Probably slow. O(n^2) in worse case.
list.remove(x)
Remove the first item from the list whose value is x. It is an error if there is no such item.
for i in list2:
list1.remove(i)
# list1 becomes
['25', '+', '/', '7']
Upvotes: 3
Reputation: 95908
Essentially, you want a difference operation on a multi-set, i.e. a bag. Python implements this for the collections.Counter
object:
Several mathematical operations are provided for combining Counter objects to produce multisets (counters that have counts greater than zero). Addition and subtraction combine counters by adding or subtracting the counts of corresponding elements. Intersection and union return the minimum and maximum of corresponding counts. Each operation can accept inputs with signed counts, but the output will exclude results with counts of zero or less.
So, for example:
>>> list1 = ["25","+","7","*","6","/","7"]
>>> list2 = ["7","*","6"]
>>> list((Counter(list1) - Counter(list2)).elements())
['25', '+', '7', '/']
In Python 3.6+ this will be ordered (although this is not currently guaranteed, and should probably be considered an implementation detail). If order is important, and you are not using this version, you may have to implement an ordered counter.
Indeed, the docs themselves provide just such a recipe:
>>> from collections import Counter, OrderedDict
>>> class OrderedCounter(Counter, OrderedDict):
... 'Counter that remembers the order elements are first encountered'
... def __repr__(self):
... return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
... def __reduce__(self):
... return self.__class__, (OrderedDict(self),)
...
>>> list((OrderedCounter(list1) - OrderedCounter(list2)).elements())
['25', '+', '/', '7']
Upvotes: 6