Python Python Collections Lists Removing items from a list

Leo Marco Corpuz
Leo Marco Corpuz
18,975 Points

removing non integers from list

I'm getting an error saying I still have more items to remove.

lists.py
messy_list = ["a", 2, 3, 1, False, [1, 2, 3]]
copyMessy=messy_list.copy()
# Your code goes below heremessy_list.pop(3)
item=messy_list.pop(3)
messy_list.insert(0,item)
for nonInt in messy_list:
    if type(nonInt)!=int:
        copyMessy.remove(nonInt)

print(copyMessy)

2 Answers

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 22,201 Points

You are getting the idea correct, but the automated grader wants to explicitly check the variable named messy_list rather than copyMessy.

Here is a slightly corrected version of your code.

messy_list = ["a", 2, 3, 1, False, [1, 2, 3]]
copyMessy=messy_list.copy()

item=messy_list.pop(3)
messy_list.insert(0,item) # your code is exactly right to this point

for nonInt in copyMessy: # here, change our iterable to copyMessy, since we're going to be changing messy_list
    if type(nonInt)!=int:
        messy_list.remove(nonInt) # finally, remove the nonInt from messy_list
Leo Marco Corpuz
Leo Marco Corpuz
18,975 Points

Thanks! However, I'm still not clear how doing a remove method while for-looping through a list wouldn't work. Is it because the for-loop follows the index order? For example, if we removed the first index(0), it would skip the next item on the list for the next iteration because its index would be 0 and the loop would work on the third list item since its index would be 1.

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 22,201 Points

This is a fantastic question, the answer to which I had to learn the hard way!

Lists are mutable (which means they can change in place). When you begin using a list as your iterable in a FOR loop and you change the iterable, you can create unexpected results. The FOR loop has an internal counter and if you delete or remove an element, you will skip an element.

From the official Python documentation section 8.3

https://docs.python.org/3/reference/compound_stmts.html#for

"There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop. This can lead to nasty bugs that can be avoided by making a temporary copy using a slice of the whole sequence, e.g.,"

Below is the classic example, remove all months that contain the letter 'r'.

months = ['January', 'February', 'March', 'April', 
          'May', ' June', 'July', 'August', 'September',
          'October', 'November', 'December']

expected = ['May', ' June', 'July', 'August']

# let's remove all months that contain the letter 'r'
for month in months:
    if 'r' in month:
        months.remove(month)

print('Months without the letter "r"')
print(months)

See... this DID NOT work, check it out below.

Months without the letter "r"
['February', 'April', 'May', ' June', 'July', 'August', 'October', 'December']

This time, we iterate over a COPY of the list.

months = ['January', 'February', 'March', 'April', 
          'May', ' June', 'July', 'August', 'September',
          'October', 'November', 'December']

# Now... this time, lets iterate over a list copy
# let's remove all months that contain the letter 'r'
for month in list(months):
    if 'r' in month:
        months.remove(month)

print('Months without the letter "r"')
print(months)

This works like we intended!

Months without the letter "r"
['May', ' June', 'July', 'August']

Another way to make a copy of a list would be like this:

for month in months[:]:
    if 'r' in month:
        months.remove(month)