tmj
tmj

Reputation: 1858

Deleting items in a list in python

Tried deleting items in a list, no success.

>>> r = [1,2,3,4,5]
>>> for i in r:
    if i<3:
        del i


>>> print r
[1, 2, 3, 4, 5]

I even tried filtering it,

>>> def f(i):
    True if i>2 else False


>>> print list(filter(f,r))
[]

I do not understand why the first one is not working. And I dont understand the result at all, when I use filter(function,iterable).

EDIT:

Seeing Paulo's comment below, now I do not understand why this works.

>>> for i in r:
    if i<3:
        r.remove(i)


>>> print r
[3, 4, 5]

Shouldn't the iterator problem be still there, and shouldn't the code end up removing only the first element (r[0])

Upvotes: 2

Views: 356

Answers (2)

Marcin
Marcin

Reputation: 49846

I do not understand why the first one is not working.

It is not working because the statement del i undefines the variable i - that is, it deletes it from the scope (global or local) which contains it.

And I dont understand the result at all, when I use filter(function,iterable)

Your function, f does not contain a return statement. Accordingly, it always returns None, which has the boolean equivalent value of False. Thus, filter excludes all values.


What you should probably be doing is filtering using a comprehension, and replacing the list, like so:

r = [i for i in r if i >= 3]

Or, if you really do want to delete part of the original list and modify it, use del on a slice of the list:

del r[:3]

Seeing Paulo's comment below, now I do not understand why [using remove] works.

Because remove(r) searches for the value r in the list, and deletes the first instance of it. Accordingly, repeated modification of the list does not affect the iteration that happens inside remove. However, note that it is still susceptible to the same error, if removal of an item leads to an item being skipped in iteration of the list.

Upvotes: 4

Martijn Pieters
Martijn Pieters

Reputation: 1122172

Use a list comprehension instead:

[i for i in r if i >= 3]

and retain instead of delete.

Your filter never returned the test; so you always return None instead and that's false in a boolean context. The following works just fine:

def f(i):
    return i > 2

Your initial attempt failed because del i unbinds i, but the list remains unaffected. Only the local name i is cleared.

If you want to delete an item from a list, you need to delete the index:

del r[0]

deletes the first element from the list.

Even if you did manage to delete indices the loop would have held some suprises:

>>> for i, element in enumerate(r):
...     if element < 3:
...         del r[i]
... 
>>> r
[2, 3, 4, 5]

This version fails because the list iterator used by the for loop doesn't know you deleted elements from the list; deleting the value at index 0 shifts up the rest of the list, but the loop iterator looks at item 1 regardless:

  • first iteration, r = [1, 2, 3, 4, 5], iterator index 0 -> element = 1
  • second iteration, r = [2, 3, 4, 5], iterator index 1 -> element = 3

Upvotes: 10

Related Questions