Ezequiel
Ezequiel

Reputation: 718

Delete many elements of list (python)

I have a list L.

I can delete element i by doing:

del L[i]

But what if I have a set of non contiguous indexes to delete?

I=set([i1, i2, i3,...])

Doing:

for i in I: 
     del L[i]

Won't work.

Any ideas?

Upvotes: 17

Views: 41445

Answers (5)

philE
philE

Reputation: 1703

You can use numpy.delete as follows:

import numpy as np
a = ['a', 'l', 3.14, 42, 'u']
I = [1, 3, 4]
np.delete(a, I).tolist()
# Returns: ['a', '3.14']

If you don't mind ending up with a numpy array at the end, you can leave out the .tolist(). You should see some pretty major speed improvements, too, making this a more scalable solution. I haven't benchmarked it, but numpy operations are compiled code written in either C or Fortran.

Upvotes: 4

cherish
cherish

Reputation: 1400

L = [ item for item in L if L.index(item) not in I ]

Upvotes: 0

Kevin Horn
Kevin Horn

Reputation: 4295

If your original list data can safely be turned into a set (i.e. all unique values and doesn't need to maintain order), you could also use set operations:

Lset = set(L)
newset = Lset.difference(I)

You could also maybe do something with a Bag/Multiset, though it probably isn't worth the effort. Paul McGuire's second listcomp solution is certainly best for most cases.

Upvotes: 1

PaulMcG
PaulMcG

Reputation: 63709

Eine Minuten bitte, Ich hap eine kleine Problemo avec diese Religione. -- Eddie Izzard (doing his impression of Martin Luther)

Deleting by reverse-iterating over a list to preserve the iterator is a common solution to this problem. But another solution is to change this into a different problem. Instead of deleting items from the list using some criteria (in your case, the index exists in a list of indexes to be deleted), create a new list that leaves out the offending items.

L[:] = [ item for i,item in enumerate(L) if i not in I ]

For that matter, where did you come up with the indexes in I in the first place? You could combine the logic of getting the indexes to be removed and building the new list. Assuming this is a list of objects and you only want to keep those that pass an isValid test:

L[:] = [ item for item in L if item.isValid() ]

This is much more straightforward than:

I = set()
for i in range(len(L)):
    if not L[i].isValid():
        I.add(i)

for i in sorted(I, reverse=True):
    del L[i]

For the most part, I turn any question about "how to delete from a list the items that I don't want" into "how to create a new list containing just the items I want".

EDITED: changed "L = ..." to "L[:] = ..." per Alex Martelli's answer to this question.

Upvotes: 32

dcrosta
dcrosta

Reputation: 26258

for i in I:
    del L[i]

won't work, because (depending on the order) you may invalidate the iterator -- this will usually show up as some items which you intended to delete remaining in the list.

It's always safe to delete items from the list in the reverse order of their indices. The easiest way to do this is with sorted():

for i in sorted(I, reverse=True):
    del L[i]

Upvotes: 9

Related Questions