tags:

views:

132

answers:

2

Suppose I have a list of numbers:

L = [1, 2, 3, 4, 5]

How do I delete an element, let's say 3, from the list while I iterate it?

I tried the following code but it didn't do it:

for el in L:
  if el == 3:
    del el

Any ideas?

Thanks, Boda Cydo.

+6  A: 

Best is usually to proceed constructively -- build the new list of the items you want instead of removing those you don't. E.g.:

L[:] = [el for el in L if el != 3]

the list comprehension builds the desired list and the assignment to the "whole-list slice", L[:], ensure you're not just rebinding a name, but fully replacing the contents, so the effects are identically equal to the "removals" you wanted to perform. This is also fast.

If you absolutely, at any cost, must do deletions instead, a subtle approach might work:

>>> ndel = 0
>>> for i, el in enumerate(list(L)):
...    if el==3:
...      del L[i-ndel]
...      ndel += 1

nowhere as elegant, clean, simple, or well-performing as the listcomp approach, but it does do the job (though its correctness is not obvious at first glance and in fact I had it wrong before an edit!-). "at any cost" applies here;-).

Looping on indices in lieu of items is another inferior but workable approach for the "must do deletions" case -- but remember to reverse the indices in this case...:

for i in reversed(range(len(L))):
  if L[i] == 3: del L[i]

indeed this was a primary use case for reversed back when we were debating on whether to add that built-in -- reversed(range(... isn't trivial to obtain without reversed, and looping on the list in reversed order is sometimes useful. The alternative

for i in range(len(L) - 1, -1, -1):

is really easy to get wrong;-).

Still, the listcomp I recommended at the start of this answer looks better and better as alternatives are examined, doesn't it?-).

Alex Martelli
Good idea. I didn't think of it. Thank you, Alex! :)
bodacydo
@bodacydo, you're welcome!
Alex Martelli
The second approach will delete the wrong elements when there's more than one element to delete, because the indices change after the first deletion.
interjay
@interjay, +1: you're right, I edited to compensate for that (unfortunately `reversed(enumerate(...` doesn't work -- `enumerate` is an iterable but not a sequence, `reversed` needs a sequence as its argument).
Alex Martelli
A: 
for el in L:
    if el == 2:
        del L[el]
myfreeweb
need to enumerate so that you can index L[idx].
Andrew Jaffe
Nope, this will behave in really weird ways indeed -- removing L's "third item" (possibly more than once) if completely unrelated items equal `2`, and often skipping an item in L when it does such removals. What a nightmare to debug...!-)
Alex Martelli