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
Nick Tillman
12,595 PointsRemoving 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?
Nick Tillman
12,595 PointsThanks, xela888! I had no clue about that, so that is definitely valuable to know.
Alexander Davison
65,469 PointsNo problem! Happy Coding!
2 Answers
Iain Simmons
Treehouse Moderator 32,305 PointsYou 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)]
Nick Tillman
12,595 PointsAmazingly 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.
Iain Simmons
Treehouse Moderator 32,305 PointsNo problem! I learned a lot from looking for a solution to this!
Ira Bradley
12,976 Pointsthe_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.
Alexander Davison
65,469 PointsAlexander Davison
65,469 Pointsif 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