-1

I am currently working with the data structure list and am wondering how to remove all elements found in one list that occur in another list. I've seen a couple of examples on Stack Overflow that spoke about removing single elements from a list but not for instances with removing more than one types of identical elements (like the example below without manually removing each instance). For example, given the two lists below:

friends_pets = ['Chicken', 'Chicken' 'Dog', 'Pigeon', 'Dog', 'Cat', 'Cat', 'Cat']
personal_pets = ['Dog', 'Cat']

I want my function to return:

>>> ['Chicken', 'Chicken', 'Pigeon']

I figured that using the filter() method to return the desired list over remove() would seem most ideal, however, I'm having difficulty accessing the information that Python is storing at a specific address.

for pet in personal_pets:
    filter(pet, friends_pets)

>>> <filter object at 0x10bfa2d90>
>>> <filter object at 0x10bfa2e50>

I even tried running:

for pet in personal_pets:
    list(filter(pet, friends_pets))

however, it states that the 'str' object is not callable.

The closest I can get using remove() is:

for pet in personal_pets:
    friends_pets.remove(pet)

>>> ['Chicken', 'Chicken', 'Pigeon', 'Dog', 'Cat', 'Cat', 'Cat']
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
AAZA
  • 1
  • 1
  • 5

2 Answers2

2

To use filter, the function used is a lambda that filters out the undesirable pets. Here, used list new so to be non-destructive of the friends_pets list. Otherwise, you could use that array instead of new.

However that approach is wasteful because it reconstructs the new array for each pet in personal_pets

>>> new = []
>>> new = [] + friends_pets
>>> for pet in personal_pets:
    new = list(filter(lambda x: x != pet, new))


>>> new
['Chicken', 'Chicken', 'Pigeon']

It could be more simply done using a list comprehension.

>>> L = [pet for pet in friends_pets if pet not in set(personal_pets)]
>>> L
['Chicken', 'Chicken', 'Pigeon']

The use of a set here would allow a speedup if the lists are large

Update: Had to add a missing comma in friends_pets

friends_pets = ['Chicken', 'Chicken', 'Dog', 'Pigeon', 'Dog', 'Cat', 'Cat', 'Cat']

It was missing between the second appearance of chicken and the dog. Oddly enough, it treated them as a single string and I don't understand why.

Chris Charley
  • 6,403
  • 2
  • 24
  • 26
0

Use a set to keep the running time in O(n) bounds.

There are multiple things you can do.

Use a generator if the input can be large:

def exclude_items(original_list, items_to_exclude):
    # Create a set as lookup time is O(1).
    # It can be O(log N) in case of collisions though still better than O(n) without it
    to_exclude = set(items_to_exclude)
    for item in original_list:
        if item not in to_exclude:
           yield item

Without a generator:

def exclude_items(original_list, items_to_exclude):
    to_exclude = set(items_to_exclude)
    return [item for item in original_list if item not in to_exclude]
Siddharth Srivastava
  • 1,059
  • 1
  • 10
  • 22