Supprimer plusieurs éléments d'une liste Python en une seule instruction

107

En python, je sais comment supprimer des éléments d'une liste.

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

Ce code ci-dessus supprime les valeurs 5 et 'item' de item_list. Mais quand il y a beaucoup de choses à supprimer, je dois écrire plusieurs lignes de

item_list.remove("something_to_remove")

Si je connais l'index de ce que je supprime, j'utilise:

del item_list[x]

où x est l'index de l'élément que je souhaite supprimer.

Si je connais l'index de tous les nombres que je veux supprimer, j'utiliserai une sorte de boucle vers delles éléments aux index.

Mais que faire si je ne connais pas les indices des éléments que je souhaite supprimer?

J'ai essayé item_list.remove('item', 'foo'), mais j'ai eu une erreur disant que cela removene prend qu'un seul argument.

Existe-t-il un moyen de supprimer plusieurs éléments d'une liste dans une seule instruction?

PS j'ai utilisé delet remove. Quelqu'un peut-il expliquer la différence entre ces deux éléments ou sont-ils identiques?

Merci

RandomCoder
la source
1
Pour répondre à votre deuxième question: delsupprime un élément par son index. La removefonction d'une liste trouve l'index d'un élément, puis appelle delcet index.
Aaron Christiansen
Double

Réponses:

159

En Python, créer un nouvel objet est souvent mieux que de modifier un existant:

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

Ce qui équivaut à:

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

Dans le cas d'une grande liste de valeurs filtrées (ici, ('item', 5)est un petit ensemble d'éléments), utiliser a setpeut conduire à une amélioration des performances, car l' inopération est en O (1):

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

Notez que, comme expliqué dans les commentaires et suggéré ici , ce qui suit pourrait gagner encore plus de temps, évitant que l'ensemble ne soit construit à chaque boucle:

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

Un filtre de bloom est également une bonne solution si la mémoire n'est pas bon marché.

Aluriak
la source
J'aime la première réponse. Je ne fais pas de nouvelle liste, ce qui est bien. Merci!
RandomCoder
L'ensemble est-il optimisé en python 2 ou est-il uniquement optimisé en python 3? Je veux dire par là que l'ensemble est créé une seule fois lorsque le bytecode est généré?
Har
L'ensemble est, par définition , optimisé pour le infonctionnement. Voir ces benchmarks pour des comparaisons des quatre structures de données primitives. Oui, l'ensemble est construit à chaque boucle, comme suggéré ici , par conséquent, enregistrer l'ensemble dans une variable dédiée à utiliser dans l'expression du générateur peut gagner du temps.
aluriak
@RandomCoder Vous créez en fait une nouvelle liste, vous réutilisez simplement un nom. Vous pouvez vérifier cela en comparant id(item_list)avant et après item_list = [e for e in item_list if e not in ('item', 5)]. Vérifiez ma réponse pour voir comment modifier une liste en place.
Darkonaut
20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

la liste finale après la suppression devrait être comme suit

final_list=[3.14, True]

Code sur une seule ligne

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

la sortie serait la suivante

final_list=[3.14, True]
Aakash Goel
la source
13
non, il mélange les éléments de la liste. À n'utiliser que si l'ordre des articles n'a pas d'importance, ce qui est souvent le cas.
scavenger
5
Cela supprimera également les doublons de la liste. Ce n'est pas que cela compte pour la liste d'exemples
tschale
1
Cette réponse est incorrecte et peut causer de sérieux bugs, pourquoi est-elle votée pour?
omerfarukdogan
1
Cela supprimera les doublons! La réponse peut provoquer de sérieux bugs, veuillez ne pas l'utiliser.
user2698178
2

Je ne sais pas pourquoi tout le monde a oublié de mentionner l'incroyable capacité de sets en python. Vous pouvez simplement convertir votre liste en un ensemble, puis supprimer tout ce que vous souhaitez supprimer dans une expression simple comme celle-ci:

>>> 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
la source
6
Cependant, ne maintient pas l'ordre des objets.
Astrid
Et supprimera également les doublons qui existent potentiellement dans la liste.
kyriakosSt
1

Je republie ma réponse d' ici parce que j'ai vu qu'elle s'inscrit également ici. Il permet de supprimer plusieurs valeurs ou de supprimer uniquement les doublons de ces valeurs et renvoie une nouvelle liste ou modifie la liste donnée en place.


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

Extension 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']
"""

Vous devez être clair sur ce que vous voulez vraiment faire, modifier une liste existante ou créer une nouvelle liste avec les éléments spécifiques manquants. Il est important de faire cette distinction au cas où vous auriez une deuxième référence pointant vers la liste existante. Si vous avez, par exemple ...

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]

Cela peut être le comportement souhaité ou non.

Darkonaut
la source
1

Vous pouvez utiliser filterfalse fonction à partir itertools Module

Exemple

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=}")

Production:

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
la source
0

Mais que faire si je ne connais pas les indices des éléments que je souhaite supprimer?

Je ne comprends pas exactement pourquoi vous n'aimez pas .remove mais pour obtenir le premier index correspondant à une valeur utilisez .index (value):

ind=item_list.index('item')

puis supprimez la valeur correspondante:

del item_list.pop[ind]

.index (valeur) obtient la première occurrence de valeur et .remove (valeur) supprime la première occurrence de valeur

aless80
la source
Pensez à utiliser del item_list[ind]au lieu de popsi vous n'avez pas besoin de la valeur de résultat.
kojiro le
-1

Vous pouvez utiliser ceci -

Supposons que nous ayons une liste, l = [1,2,3,4,5]

Nous voulons supprimer les deux derniers éléments d'une seule instruction

del l[3:]

Nous avons la sortie:

l = [1,2,3]

Rester simple

Krishna Singhal
la source