2012-10-01 50 views
10

¿Cómo elimino un elemento de una lista si coincide con una subcadena?Eliminar un elemento de la lista que coincide con una subcadena - Python

He intentado quitar un elemento de una lista utilizando el método pop() y enumerate pero parece que me estoy perdiendo un par de elementos contiguos que necesita ser eliminado:

sents = ['@$\tthis sentences needs to be removed', 'this doesnt', 
    '@$\tthis sentences also needs to be removed', 
    '@$\tthis sentences must be removed', 'this shouldnt', 
    '# this needs to be removed', 'this isnt', 
    '# this must', 'this musnt'] 

for i, j in enumerate(sents): 
    if j[0:3] == "@$\t": 
    sents.pop(i) 
    continue 
    if j[0] == "#": 
    sents.pop(i) 

for i in sents: 
    print i 

Salida:

this doesnt 
@$ this sentences must be removed 
this shouldnt 
this isnt 
#this should 
this musnt 

salida deseada:

this doesnt 
this shouldnt 
this isnt 
this musnt 
+3

Caso clásico de eliminación de elementos de una lista mientras itera sobre esa lista. Lea las docenas de otras preguntas sobre el desbordamiento de pila que se relacionan con esto. Además, consulte la [nota en los documentos] (http://docs.python.org/reference/compound_stmts.html#for). –

+1

siempre debe evitar cambiar la longitud de un contenedor mientras lo itera, esta es una receta para el desastre – wim

+0

En general, generalmente es mejor crear una nueva lista filtrada que intentar modificar una lista en contexto. Los algoritmos inmutables siempre son más fáciles de razonar (aunque no siempre es más fácil descifrar cómo escribir). Cuando solo está reemplazando valores, a veces las ganancias de eficiencia de trabajar in situ superan eso, pero cuando está eliminando o insertando en el medio de una lista, por lo general está obteniendo _worse_ efficiency junto con su lógica menos robusta. – abarnert

Respuesta

20

Cómo abo ut algo tan simple como:

>>> [x for x in sents if not x.startswith('@$\t') and not x.startswith('#')] 
['this doesnt', 'this shouldnt', 'this isnt', 'this musnt'] 
+0

ah una lista de comprensión, elegante! Déjame intentarlo. – alvas

+0

+1 para la respuesta más limpia. – abarnert

8

Esto debería funcionar:

[i for i in sents if not ('@$\t' in i or '#' in i)] 

Si desea que sólo las cosas que comienzan con las especificadas oracional utilizar el método str.startswith(stringOfInterest)

+2

Yo diría que este es mejor que los otros dos por no asumir que las subcadenas están en el inicio – Frikster

9

Otra técnica que utiliza filter

filter(lambda s: not (s[0:3]=="@$\t" or s[0]=="#"), sents) 

El problema con su orientación original h es cuando está en el elemento de lista i y determina que debe eliminarse, lo elimina de la lista, que desliza el elemento i+1 en la posición i. La siguiente iteración del ciclo está en el índice i+1 pero el artículo es realmente i+2.

¿Tiene sentido?

+0

¡gracias por la explicación! Apareciendo una lista mientras enumerar es realmente tonto. jajaja .. – alvas

+0

+1 para explicar el problema. – abarnert

Cuestiones relacionadas