¿Cómo eliminar un elemento de una lista si existe?
Obtengo new_tag
de un campo de texto de formulario con self.response.get("new_tag")
y selected_tags
de campos de casilla de verificación con
self.response.get_all("selected_tags")
Los combino así:
tag_string = new_tag
new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
( f1.striplist
es una función que elimina los espacios en blanco dentro de las cadenas de la lista).
Pero en el caso de que tag_list
esté vacío (no se ingresan nuevas etiquetas) pero hay algunas selected_tags
, new_tag_list
contiene una cadena vacía " "
.
Por ejemplo, de logging.info
:
new_tag
selected_tags[u'Hello', u'Cool', u'Glam']
new_tag_list[u'', u'Hello', u'Cool', u'Glam']
¿Cómo me deshago de la cadena vacía?
Si hay una cadena vacía en la lista:
>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> i = s.index("")
>>> del s[i]
>>> s
[u'Hello', u'Cool', u'Glam']
Pero si no hay una cadena vacía:
>>> s = [u'Hello', u'Cool', u'Glam']
>>> if s.index(""):
i = s.index("")
del s[i]
else:
print "new_tag_list has no empty string"
Pero esto da:
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
if new_tag_list.index(""):
ValueError: list.index(x): x not in list
¿Por qué sucede esto y cómo puedo solucionarlo?
1) Estilo casi inglés:
Pruebe la presencia utilizando el in
operador y luego aplique el remove
método.
if thing in some_list: some_list.remove(thing)
El remove
método eliminará solo la primera aparición de thing
, para eliminar todas las apariciones que pueda utilizar while
en lugar de if
.
while thing in some_list: some_list.remove(thing)
- Bastante simple, probablemente mi elección. Para listas pequeñas (no puedo resistirme a las frases ingeniosas)
2) Tipo pato , estilo EAFP :
Esta actitud de disparar primero, hacer preguntas al final es común en Python. En lugar de probar de antemano si el objeto es adecuado, simplemente realice la operación y detecte las excepciones relevantes:
try:
some_list.remove(thing)
except ValueError:
pass # or scream: thing not in some_list!
except AttributeError:
call_security("some_list not quacking like a list!")
Por supuesto, la segunda cláusula excepto en el ejemplo anterior no sólo tiene un humor cuestionable sino que es totalmente innecesaria (el objetivo era ilustrar la escritura de pato para las personas que no están familiarizadas con el concepto).
Si espera que ocurran varias cosas:
while True:
try:
some_list.remove(thing)
except ValueError:
break
- un poco detallado para este caso de uso específico, pero muy idiomático en Python.
- esto funciona mejor que el n.° 1
- PEP 463 propuso una sintaxis más corta para el uso simple try/except que sería útil aquí, pero no fue aprobada.
Sin embargo, con el administrador de contexto suprimir() de contextlib (introducido en Python 3.4), el código anterior se puede simplificar a esto:
with suppress(ValueError, AttributeError):
some_list.remove(thing)
Nuevamente, si espera que algo ocurra varias veces:
with suppress(ValueError):
while True:
some_list.remove(thing)
3) Estilo funcional:
Alrededor de 1993, Python obtuvo lambda
, y , cortesía de un hacker reduce()
de Lisp que los extrañó y envió parches que funcionaban*. Puede utilizar para eliminar elementos de la lista:filter()
map()
filter
is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)
Hay un atajo que puede ser útil para su caso: si desea filtrar elementos vacíos (de hecho, elementos donde bool(item) == False
, como None
, cero, cadenas vacías u otras colecciones vacías), puede pasar Ninguno como primer argumento:
cleaned_list = filter(None, some_list)
- [actualización] : en Python 2.x,
filter(function, iterable)
solía ser equivalente a[item for item in iterable if function(item)]
(o[item for item in iterable if item]
si el primer argumento esNone
); en Python 3.x, ahora es equivalente a(item for item in iterable if function(item))
. La sutil diferencia es que el filtro se utiliza para devolver una lista, ahora funciona como una expresión generadora; esto está bien si solo está iterando sobre la lista limpia y descartándola, pero si realmente necesita una lista, debe incluir lafilter()
llamada. con ellist()
constructor. - *Estas construcciones con sabor a Lispy se consideran un poco extrañas en Python. Alrededor de 2005, Guido incluso estaba hablando de eliminarlo
filter
, junto con sus compañerosmap
yreduce
(aún no se han ido, peroreduce
se trasladaron al módulo functools , que vale la pena echarle un vistazo si le gustan las funciones de alto nivel ).
4) Estilo matemático:
Las listas por comprensión se convirtieron en el estilo preferido para la manipulación de listas en Python desde que PEP 202 las introdujo en la versión 2.0 . La razón detrás de esto es que las listas por comprensión proporcionan una forma más concisa de crear listas en situaciones en las que actualmente se usarían bucles map()
y filter()
/o anidados.
cleaned_list = [ x for x in some_list if x is not thing ]
Las expresiones generadoras fueron introducidas en la versión 2.4 por PEP 289 . Una expresión generadora es mejor para situaciones en las que realmente no necesita (o no desea) tener una lista completa creada en la memoria, como cuando solo desea iterar sobre los elementos uno a la vez. Si solo está iterando sobre la lista, puede pensar en una expresión generadora como una lista de comprensión evaluada de forma diferida :
for item in (x for x in some_list if x is not thing):
do_your_thing_with(item)
- Vea esta publicación de blog sobre la historia de Python de GvR .
- Esta sintaxis está inspirada en la notación matemática del constructor de conjuntos .
- Python 3 también ha establecido y dictado por comprensión .
Notas
- es posible que desee utilizar el operador de desigualdad
!=
en lugar deis not
( la diferencia es importante ) - para los críticos de los métodos que implican una copia de la lista: contrariamente a la creencia popular, las expresiones generadoras no siempre son más eficientes que las listas por comprensión; perfile antes de quejarse
Como una sola línea:
>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> s.remove('') if '' in s else None # Does nothing if '' not in s
>>> s
['Hello', 'Cool', 'Glam']
>>>