4

Given 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 over it?

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

for el in L:
    if el == 3:
        del el
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
bodacydo
  • 75,521
  • 93
  • 229
  • 319
  • This asking is not very good or generic, because it only asks about removing the first element matching a specific value, for which Python already has `L.remove(3)` builtin, or list comprehensions. But this asking won't cover all the more general cases like *"Remove duplicate adjacent values in a sorted list"*. – smci Jan 02 '22 at 05:59
  • It's not clear what OP wanted in this question. Depending on the intent, either of the linked duplicates would be appropriate. – Karl Knechtel Jul 04 '22 at 02:00

2 Answers2

13

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
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Good idea. I didn't think of it. Thank you, Alex! :) – bodacydo Mar 14 '10 at 15:39
  • 1
    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 Mar 14 '10 at 15:47
  • @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 Mar 14 '10 at 15:58
-4
for el in L:
    if el == 2:
        del L[el]
myfreeweb
  • 971
  • 1
  • 13
  • 19
  • need to enumerate so that you can index L[idx]. – Andrew Jaffe Mar 14 '10 at 15:43
  • 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 Mar 14 '10 at 15:44