2009-09-20 20 views
12

Tengo una lista L.muchos elementos de la lista (Python)

que puede eliminar el elemento i haciendo:

del L[i] 

Pero lo que si tengo un conjunto de índices no contiguos eliminar?

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

Haciendo:

for i in I: 
    del L[i] 

no funcionará.

¿Alguna idea?

+1

dupe http://stackoverflow.com/questions/497426/deleting-multiple-elements-from-a-list – SilentGhost

Respuesta

31

Eine Minuten bitte, Ich hap Eine kleine Problemo avec diese Religione. - Eddie Izzard (haciendo su impresión de Martin Luther)

Borrado en más de una lista de preservar el iterador la iteración inversa es una solución común a este problema. Pero otra solución es cambiar esto en un problema diferente. En lugar de eliminar elementos de la lista utilizando algunos criterios (en su caso, el índice existe en una lista de índices que se eliminarán), cree una nueva lista que omita los elementos ofensivos.

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

Por lo demás, en donde se les ocurrió con los índices en I en el primer lugar? Podría combinar la lógica de eliminar los índices y crear la nueva lista. Asumiendo que esto es una lista de objetos y sólo se quieren mantener los que pasan una isValid prueba:

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

Esto es mucho más sencillo que:

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] 

En su mayor parte, vuelvo a cualquier pregunta sobre "cómo eliminar de una lista los ítems que no quiero" en "cómo crear una nueva lista que contenga solo los ítems que quiero".

EDITADO: cambió "L = ..." a "L [:] = ..." según la respuesta de Alex Martelli al this question.

+0

¿Qué tan bien escala eso en listas grandes? – jmucchiello

+1

Resulta que esto mejora cuanto más largas son las listas. Vea este código de prueba: http://pastebin.com/f5bf9e3e8. – PaulMcG

+0

Esta es la forma de hacerlo; tenga en cuenta que "I" debería ser un conjunto, no una lista. –

9
for i in I: 
    del L[i] 

no va a funcionar, porque (en función de la orden) puede invalidar el iterador - lo cual suele aparecer como algunos artículos que se pretende eliminar queda en la lista.

Siempre es seguro eliminar elementos de la lista en el orden inverso de sus índices. La forma más sencilla de hacerlo es con la ordenada():

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

Esa es una gran idea. : D No estoy seguro de si está invertido (lista (I)) es correcto? Pero entiendo la idea: clasifique los índices en I en orden inverso y LUEGO elimínelos. – Ezequiel

+0

necesita la lista() ya que no puede llamar a reversed() directamente en un conjunto. – dcrosta

+0

ack, eso fue una tontería! no quise decir invertido (list (...)), quise decir ordenado (..., reverse = True) – dcrosta

1

Si sus datos de listas originales con seguridad se puede convertir en un conjunto (es decir, todos los valores únicos y no necesita para mantener el orden), también se puede utilizar operaciones de conjuntos:

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

También podría tal vez hacer algo con una bolsa/Multiset, aunque probablemente no vale la pena el esfuerzo. La segunda solución listcomp de Paul McGuire es ciertamente la mejor para la mayoría de los casos.

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

Puede utilizar numpy.delete de la siguiente manera:

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

Si no le importa terminar con una matriz numpy al final, se puede dejar de lado el .tolist(). Debería ver algunas mejoras de velocidad bastante importantes, también, haciendo que esta sea una solución más escalable. No lo he comparado, pero las operaciones numpy son código compilado escrito en C o Fortran.

Cuestiones relacionadas