Elimina varios elementos de una lista de Python en una sola declaración

107

En Python, sé cómo eliminar elementos de una lista.

item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)

Este código anterior elimina los valores 5 y 'item' de item_list. Pero cuando hay muchas cosas que eliminar, tengo que escribir muchas líneas de

item_list.remove("something_to_remove")

Si conozco el índice de lo que estoy eliminando, uso:

del item_list[x]

donde x es el índice del elemento que quiero eliminar.

Si conozco el índice de todos los números que quiero eliminar, usaré algún tipo de bucle para dellos elementos de los índices.

Pero, ¿qué pasa si no conozco los índices de los elementos que quiero eliminar?

Lo intenté item_list.remove('item', 'foo'), pero recibí un error que decía que removesolo se necesita un argumento.

¿Existe alguna forma de eliminar varios elementos de una lista en una sola declaración?

PD: he usado dely remove. ¿Alguien puede explicar la diferencia entre estos dos o son iguales?

Gracias

RandomCoder
fuente
1
Para responder a su segunda pregunta: delelimina un elemento por su índice. La removefunción de una lista encuentra el índice de un elemento y luego llama dela ese índice.
Aaron Christiansen
Posible duplicado de Eliminar varios elementos de una lista
IMLD

Respuestas:

159

En Python, crear un nuevo objeto suele ser mejor que modificar uno existente:

item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]

Que es equivalente a:

item_list = ['item', 5, 'foo', 3.14, True]
new_list = []
for e in item_list:
    if e not in ('item', 5):
        new_list.append(e)
item_list = new_list

En caso de una gran lista de valores filtrados (aquí, ('item', 5)hay un pequeño conjunto de elementos), use un setpuede conducir a una mejora del rendimiento, ya que la inoperación está en O (1):

item_list = [e for e in item_list if e not in {'item', 5}]

Tenga en cuenta que, como se explica en los comentarios y se sugiere aquí , lo siguiente podría ahorrar aún más tiempo, evitando que el conjunto se construya en cada bucle:

unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]

Un filtro de floración también es una buena solución si la memoria no es barata.

aluriak
fuente
Me gusta la primera respuesta. No voy a hacer una nueva lista, lo cual es bueno. ¡Gracias!
RandomCoder
¿El conjunto está optimizado en Python 2 o solo está optimizado en Python 3? Con eso quiero decir, ¿el conjunto se crea solo una vez cuando se genera el código de bytes?
Har
El conjunto está, por definición , optimizado para su infuncionamiento. Consulte estos puntos de referencia para obtener comparaciones de las cuatro estructuras de datos primitivas. Sí, el conjunto se construye en cada bucle, como se sugiere aquí , por lo tanto, guardar el conjunto en una variable dedicada para usar en la expresión del generador puede ahorrar tiempo.
aluriak
@RandomCoder Realmente haces una nueva lista, simplemente reutilizas un nombre. Puede comprobarlo comparando id(item_list)antes y después item_list = [e for e in item_list if e not in ('item', 5)]. Verifique mi respuesta para ver cómo modificar una lista en su lugar.
Darkonaut
20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

La lista final después de la eliminación debe ser la siguiente

final_list=[3.14, True]

Código de línea única

final_list= list(set(item_list).difference(set(list_to_remove)))

la salida sería la siguiente

final_list=[3.14, True]
Aakash Goel
fuente
13
no, baraja los elementos de la lista. Úselo solo si el orden de los elementos no importa, lo que ocurre con bastante frecuencia.
carroñero
5
Esto también eliminará los duplicados de la lista. Sin embargo, no es que importe para la lista de ejemplos
tschale
1
Esta respuesta es incorrecta y puede causar errores graves, ¿por qué se vota a favor?
omerfarukdogan
1
¡Eliminará los duplicados! La respuesta puede causar errores graves, no la utilice.
user2698178
2

No sé por qué todos olvidaron mencionar la asombrosa capacidad de sets en Python. Simplemente puede convertir su lista en un conjunto y luego eliminar lo que desee eliminar en una expresión simple como esta:

>>> item_list = ['item', 5, 'foo', 3.14, True]
>>> item_list = set(item_list) - {'item', 5}
>>> item_list
{True, 3.14, 'foo'}
>>> # you can cast it again in a list-from like so
>>> item_list = list(item_list)
>>> item_list
[True, 3.14, 'foo']
Anwarvic
fuente
6
Sin embargo, no mantiene el orden de los objetos.
Astrid
Y también eliminará los duplicados que puedan existir en la lista.
kyriakosSt
1

Estoy volviendo a publicar mi respuesta desde aquí porque vi que también encaja aquí. Permite eliminar múltiples valores o eliminar solo duplicados de estos valores y devuelve una nueva lista o modifica la lista dada en su lugar.


def removed(items, original_list, only_duplicates=False, inplace=False):
    """By default removes given items from original_list and returns
    a new list. Optionally only removes duplicates of `items` or modifies
    given list in place.
    """
    if not hasattr(items, '__iter__') or isinstance(items, str):
        items = [items]

    if only_duplicates:
        result = []
        for item in original_list:
            if item not in items or item not in result:
                result.append(item)
    else:
        result = [item for item in original_list if item not in items]

    if inplace:
        original_list[:] = result
    else:
        return result

Extensión Docstring:

"""
Examples:
---------

    >>>li1 = [1, 2, 3, 4, 4, 5, 5]
    >>>removed(4, li1)
       [1, 2, 3, 5, 5]
    >>>removed((4,5), li1)
       [1, 2, 3]
    >>>removed((4,5), li1, only_duplicates=True)
       [1, 2, 3, 4, 5]

    # remove all duplicates by passing original_list also to `items`.:
    >>>removed(li1, li1, only_duplicates=True)
      [1, 2, 3, 4, 5]

    # inplace:
    >>>removed((4,5), li1, only_duplicates=True, inplace=True)
    >>>li1
        [1, 2, 3, 4, 5]

    >>>li2 =['abc', 'def', 'def', 'ghi', 'ghi']
    >>>removed(('def', 'ghi'), li2, only_duplicates=True, inplace=True)
    >>>li2
        ['abc', 'def', 'ghi']
"""

Debe tener claro lo que realmente quiere hacer, modificar una lista existente o hacer una nueva lista con los elementos específicos que faltan. Es importante hacer esa distinción en caso de que tenga una segunda referencia que apunte a la lista existente. Si tienes, por ejemplo ...

li1 = [1, 2, 3, 4, 4, 5, 5]
li2 = li1
# then rebind li1 to the new list without the value 4
li1 = removed(4, li1)
# you end up with two separate lists where li2 is still pointing to the 
# original
li2
# [1, 2, 3, 4, 4, 5, 5]
li1
# [1, 2, 3, 5, 5]

Este puede ser o no el comportamiento que desea.

Darkonaut
fuente
1

Puede utilizar filterfalse función de itertools módulo

Ejemplo

import random
from itertools import filterfalse

random.seed(42)

data = [random.randrange(5) for _ in range(10)]
clean = [*filterfalse(lambda i: i == 0, data)]
print(f"Remove 0s\n{data=}\n{clean=}\n")


clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1s\n{data=}\n{clean=}")

Salida:

Remove 0s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 1, 1, 1, 4, 4]

Remove 0s and 1s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 4, 4]
Vlad Bezden
fuente
0

Pero, ¿qué pasa si no conozco los índices de los elementos que quiero eliminar?

No entiendo exactamente por qué no le gusta .remove, pero para obtener el primer índice correspondiente a un valor, use .index (value):

ind=item_list.index('item')

luego elimine el valor correspondiente:

del item_list.pop[ind]

.index (valor) obtiene la primera aparición de valor y .remove (valor) elimina la primera aparición de valor

aless80
fuente
Considere usar en del item_list[ind]lugar de popsi no necesita el valor de resultado.
kojiro
-1

Puedes usar esto -

Supongamos que tenemos una lista l = [1,2,3,4,5]

Queremos eliminar los dos últimos elementos en una sola declaración.

del l[3:]

Tenemos salida:

l = [1,2,3]

Mantenlo simple

Krishna Singhal
fuente