1

For quite a bit of time now I have been trying to figure out a way to loop through a list and remove the current item that I'm at. I can't seem to get this working as I would like it to. It loops just 1 time through, but I wanted it to loop 2 times. When I remove the removal line - it loops 2 times.

a = [0, 1]
for i in a:
    z = a
    print z.remove(i)

The output:

[1]

The output that I was expecting:

[1] 
[0]
agf
  • 171,228
  • 44
  • 289
  • 238
  • i'm not sure why you get any output at all. i thought `z.remove(i)` will return `None`. – wim Aug 29 '11 at 07:19

4 Answers4

8

You're changing the list while iterating over it -- z = a doesn't make a copy, it just points z at the same place a points.

Try

for i in a[:]:          # slicing a list makes a copy
    print i             # remove doesn't return the item so print it here
    a.remove(i)         # remove the item from the original list

or

while a:                # while the list is not empty
    print a.pop(0)      # remove the first item from the list

If you don't need an explicit loop, you can remove items that match a condition with a list comprehension:

a = [i for i in a if i] # remove all items that evaluate to false
a = [i for i in a if condition(i)] # remove items where the condition is False
agf
  • 171,228
  • 44
  • 289
  • 238
  • The output now is "None None" –  Aug 29 '11 at 07:00
  • `remove` doesn't return anything, so it prints `None`. If you want to print the item before you remove it, just do `print i` then `a.remove(i)`. The `pop` version actually returns the item at the given index, so it will `print` the item. Edited my answer to reflect this. – agf Aug 29 '11 at 07:05
3

It is bad practice modify a list while you're looping through it. Create a copy of the list:

oldlist = ['a', 'b', 'spam', 'c']
newlist = [x for x in oldlist if x != 'spam']

To modify the original list, write the copy back in-place with a slice assignment:

oldlist[:] = [x for x in oldlist if x != 'spam']

† For a gist of why this might be bad practice, consider the implementation details of what goes on with the iterator over the sequence when the sequence changes during iteration. If you've removed the current item, should the iterator point to the next item in the original list or to the next item in the modified list? What if your decision procedure instead removes the previous (or next) item to the current?

wim
  • 338,267
  • 99
  • 616
  • 750
2

The problem is that you're modifying a with remove so the loop exits because the index is now past the end of it.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
1

Don't try to remove multiple items of a list while looping the list. I think it's a general rule you should follow not only in python but also in other programming languages as well.

You could add the item to be removed into a separate list. And then remove all objects in that new list from the original list.

Ryan Ye
  • 3,159
  • 1
  • 22
  • 26