Physicist
Physicist

Reputation: 3048

How to delete elements in a list based on another list?

Suppose I have a list called icecream_flavours, and two lists called new_flavours and unavailable. I want to remove the elements in flavours that appear in 'unavailable', and add those in new_flavours to the original one. I wrote the following program:

for i in unavailable:
    icecream_flavours.remove(i)

for j in new_flavours:
    icecream_flavours.append(j)

the append one is fine, but it keeps showing 'ValueError: list.remove(x): x not in list' for the first part of the program. What's the problem?

thanks

Upvotes: 0

Views: 46

Answers (4)

abarnert
abarnert

Reputation: 365807

There are two possibilities here.

First, maybe there should never be anything in unavailable that wasn't in icecream_flavours, but, because of some bug elsewhere in your program, that isn't true. In that case, you're going to need to debug where things first go wrong, whether by running under the debugger or by adding print calls all over the code. At any rate, since the problem is most likely in code that you haven't shown us here, we can't help if that's the problem.

Alternatively, maybe it's completely reasonable for something to appear in unavailable even though it's not in icecream_flavours, and in that case you just want to ignore it.

That's easy to do, you just need to write the code that does it. As the docs for list.remove explain, it:

raises ValueError when x is not found in s.

So, if you want to ignore cases when i is not found in icecream_flavours, just use a try/except:

for i in unavailable:
    try:
        icecream_flavours.remove(i)
    except ValueError:
        # We already didn't have that one... which is fine
        pass

That being said, there are better ways to organize your code.

First, using the right data structure always makes things easier. Assuming you don't want duplicate flavors, and the order of flavors doesn't matter, what you really want here is sets, not lists. And if you had sets, this would be trivial:

icecream_flavours -= unavailable
icecream_flavours |= new_flavours

Even if you can't do that, it's usually simpler to create a new list than to mutate one in-place:

icecream_flavours = [flavour for flavour in icecream_flavours 
                     if flavour not in set(unavailable)]

(Notice that I converted unavailable to a set, so we don't have to brute-force search for each flavor in a list.)

Either one of these changes makes the code shorter, and makes it more efficient. But, more importantly, they both make the code easier to reason about, and eliminate the possibility of bugs like the one you're trying to fix.

Upvotes: 1

John La Rooy
John La Rooy

Reputation: 304255

Your error is caused because unavailable contains flavours that are not in icecream_flavours.

Unless order is important, you could use set instead of list as they have operations for differences and unions and you don't need to worry about duplicates

If you must use lists, a list comprehension is a better way to filter the list

icecream_flavours = [x for x in icecream_flavours if x not in unavaiable]

You can extend the list of flavours like this

icecream_flavours += new_flavours

assuming there are no duplicates.

Upvotes: 1

Tim Zimmermann
Tim Zimmermann

Reputation: 6420

If you first want to remove all the unavailable flavours from icecream_flavours and then add the new flavours, you can use this list comprehension:

icecream_flavours = [i for i in icecream_flavours if i not in unavailable] + new_flavours

Upvotes: 1

Cory Kramer
Cory Kramer

Reputation: 117886

To add all the new_flavours that are not unavailable, you can use a list comprehension, then use the += operator to add it to the existing flavors.

icecream_flavours += [i for i in new_flavours if i not in unavailable]

If there are already flavors in the original list you want to remove, you can remove them in the same way

icecream_flavours = [i for i in icecream_flavours if i not in unavailable]

Upvotes: 1

Related Questions