Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Removing a list from a list

I can't figure out why the below will work to remove the item from the list:

the_list = ["a", 2, 3, 1, False, [1, 2, 3]]

for item in the_list:
    if isinstance(item, str):
        del the_list[the_list.index(item)]
    elif isinstance(item, bool):
        del the_list[the_list.index(item)]

for item in the_list:
    if isinstance(item, list):
        del the_list[the_list.index(item)]

when the following will not:

the_list = ["a", 2, 3, 1, False, [1, 2, 3]]

for item in the_list:
    if isinstance(item, str):
        del the_list[the_list.index(item)]
    elif isinstance(item, bool):
        del the_list[the_list.index(item)]
    elif isinstance(item, list):
        del the_list[the_list.index(item)]

Is there something I am missing about the way "elif" works or the process of removing a list from a list that would require a separate "for" loop in order for it work properly?

if you have an "if" statement and a "elif" statement, you MUST use the "else" statement. (you can use the keyword "pass" in the else statement so it wouldn't do anything.). Hope it helps! And happy coding! ~xela888

Thanks, xela888! I had no clue about that, so that is definitely valuable to know.

No problem! Happy Coding!

2 Answers

You don't have to have an else block, especially if all it will contain is pass.

The real reason your code doesn't work is because when you delete items from a list that you're looping through, it doesn't recalculate the length or the current index, so you kind of 'skip' items.

To see what is happening, add a print(type(item), item) to the start of your loop:

>>> the_list = ["a", 2, 3, 1, False, [1, 2, 3]]
>>>
>>> for item in the_list:
...     print(type(item), item)
...     if isinstance(item, str):
...         del the_list[the_list.index(item)]
...     elif isinstance(item, bool):
...         del the_list[the_list.index(item)]
...     elif isinstance(item, list):
...         del the_list[the_list.index(item)]
...
<class 'str'> a
<class 'int'> 3
<class 'int'> 1
<class 'bool'> False

As you can see, it prints the string a right at the beginning. Then it deletes that item from the list, and then moves to the item at index 1, which is now the integer 3. It prints that, moves on, prints the integer 1, moves on, prints the boolean False, deletes it, tries to move to the item at index 5, but realises it has reached the end of the list (because you now only have 4 items), so it exits the loop.

In the first lot of code you shared, it would do another loop based on the list with 4 items, and not finding any strings or booleans, would successfully delete the list.

To get around this behaviour, you could either create a new list of the items you want to keep and just reassign the value of the_list to it, use a counter variable and a while loop and decrement it when you delete something so it doesn't skip items, filter the list and reassign the results to the original, or loop over a copy of the list.

I would suggest the last option, as it is the easiest (though if you had a very large list, probably not the most efficient). Note the slice syntax [:], which just means every item in the list:

the_list = ["a", 2, 3, 1, False, [1, 2, 3]]

for item in the_list[:]:
    if isinstance(item, str):
        del the_list[the_list.index(item)]
    elif isinstance(item, bool):
        del the_list[the_list.index(item)]
    elif isinstance(item, list):
        del the_list[the_list.index(item)]

Amazingly thorough! Thanks a ton for the insights. I hadn't thought that the deletion of things from the list would throw off the loop, but it makes sense. Definitely appreciated.

No problem! I learned a lot from looking for a solution to this!

the_list = ["a", 2, 3, 1, False, [1, 2, 3]]

for item in the_list:
    if isinstance(item, str):
        del the_list[the_list.index(item)]
    elif isinstance(item, bool):
        del the_list[the_list.index(item)]
    if isinstance(item, list):
        del the_list[the_list.index(item)]

Other people have explained the 'why' but this code block would work.