Supprimer toutes les occurrences d'une valeur d'une liste?


378

En Python remove()supprimera la première occurrence de valeur dans une liste.

Comment supprimer toutes les occurrences d'une valeur d'une liste?

Voici ce que j'ai en tête:

>>> remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
[1, 3, 4, 3]

Réponses:


507

Approche fonctionnelle:

Python 3.x

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter((2).__ne__, x))
[1, 3, 3, 4]

ou

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter(lambda a: a != 2, x))
[1, 3, 3, 4]

Python 2.x

>>> x = [1,2,3,2,2,2,3,4]
>>> filter(lambda a: a != 2, x)
[1, 3, 3, 4]

120
Utilisez la compréhension de la liste sur le filtre + lambda; le premier est plus lisible en plus d'être généralement plus efficace.
habnabit

17
s / généralement / généralement étant /
habnabit

99
Le code pour la suggestion de habnabit ressemble à ceci:[y for y in x if y != 2]
coredumperror

8
Je n'appellerais pas cette solution la meilleure. Les compréhensions de liste sont plus rapides et plus faciles à comprendre tout en parcourant le code. Ce serait plutôt une méthode Perl que Python.
Peter Nimroot

3
-1 pour invoquer directement __ne__. La comparaison de deux valeurs est un processus beaucoup plus complexe que le simple appel __eq__ou l' __ne__une d'elles. Cela peut fonctionner correctement ici car vous ne comparez que des nombres, mais dans le cas général, c'est incorrect et un bug.
Aran-Fey

212

Vous pouvez utiliser une liste de compréhension:

def remove_values_from_list(the_list, val):
   return [value for value in the_list if value != val]

x = [1, 2, 3, 4, 2, 2, 3]
x = remove_values_from_list(x, 2)
print x
# [1, 3, 4, 3]

7
Comment supprimer des éléments sans les vérifier?
Alexander Ljungberg

18
Cela ne modifie pas la liste d'origine mais renvoie une nouvelle liste.
John Y

6
@Selinap: Non, c'est optimal car il ne balaye la liste qu'une seule fois. Dans votre code d'origine, l' inopérateur et la removeméthode parcourent la liste entière (jusqu'à ce qu'ils trouvent une correspondance), vous finissez donc par parcourir la liste plusieurs fois de cette façon.
John Kugelman

4
@mhawke, @John Y: utilisez simplement x [:] = ... au lieu de x = et il sera "en place" plutôt que de simplement relier le nom 'x' (la vitesse est essentiellement la même et BEAUCOUP plus rapide que x .remove peut être !!!).
Alex Martelli

10
Je vote cela parce qu'après 6 ans de Python, je ne comprends toujours pas Lambdas :)
Benjamin

107

Vous pouvez utiliser l'affectation de tranche si la liste d'origine doit être modifiée, tout en utilisant une compréhension de liste efficace (ou une expression de générateur).

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]

1
@Selinap: le filtre ne modifie pas la liste, il renvoie une nouvelle liste.
EM

les compréhensions de filtre et de liste ne modifient pas une liste. l'affectation de tranche le fait. et l'exemple original fait.
A. Coady

7
J'aime cela parce qu'il modifie la liste à laquelle x fait référence. S'il existe d'autres références à cette liste, elles seront également affectées. Cela contraste avec les x = [ v for v in x if x != 2 ]propositions, qui créent une nouvelle liste et modifient x pour s'y référer, laissant la liste d'origine intacte.
Hannes

40

Répéter la solution du premier message de manière plus abstraite:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]

19
C'est O (n * n), cependant.
Hannes

@Hannes ne serait-ce pas O (n) car il ne passe par la boucle qu'une seule fois et en même temps supprime l'article?
penta

1
Considérez x = [1] * 10000 + [2] * 1000. Le corps de la boucle s'exécute 1000 fois et .remove () doit ignorer 10000 éléments chaque fois qu'il est invoqué. Cela me sent comme O (n * n) mais ce n'est pas une preuve. Je pense que la preuve serait de supposer que le nombre de 2 dans la liste est proportionnel à sa longueur. Ce facteur de proportionnalité disparaît alors en notation big-O. Le meilleur cas, cependant, d'un nombre constant de 2 seulement dans la liste, n'est pas O (n ^ 2), juste O (2n) qui est O (n).
Hannes

23

Voir la solution simple

>>> [i for i in x if i != 2]

Cela renverra une liste contenant tous les éléments de xsans2


11

Toutes les réponses ci-dessus (à l'exception de celles de Martin Andersson) créent une nouvelle liste sans les éléments souhaités, plutôt que de supprimer les éléments de la liste d'origine.

>>> import random, timeit
>>> a = list(range(5)) * 1000
>>> random.shuffle(a)

>>> b = a
>>> print(b is a)
True

>>> b = [x for x in b if x != 0]
>>> print(b is a)
False
>>> b.count(0)
0
>>> a.count(0)
1000

>>> b = a
>>> b = filter(lambda a: a != 2, x)
>>> print(b is a)
False

Cela peut être important si vous avez d'autres références à la liste.

Pour modifier la liste en place, utilisez une méthode comme celle-ci

>>> def removeall_inplace(x, l):
...     for _ in xrange(l.count(x)):
...         l.remove(x)
...
>>> removeall_inplace(0, b)
>>> b is a
True
>>> a.count(0)
0

En ce qui concerne la vitesse, les résultats sur mon ordinateur portable sont (tous sur une liste de 5000 entrées avec 1000 entrées supprimées)

  • Compréhension de liste - ~ 400us
  • Filtre - ~ 900us
  • Boucle .remove () - 50 ms

La boucle .remove est donc environ 100 fois plus lente ........ Hmmm, peut-être qu'une approche différente est nécessaire. Le plus rapide que j'ai trouvé utilise la compréhension de la liste, mais remplacez ensuite le contenu de la liste d'origine.

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeall_replace () - 450us

Pourquoi ne pas simplement réaffecter la nouvelle liste sous l'ancienne adresse? def remove_all(x, l): return [y for y in l if y != x]puisl = remove_all(3,l)
Dannid

@Dannid C'est la deuxième méthode dans la première zone de code. Il crée une nouvelle liste et vous ne modifiez pas l'ancienne liste. Toute autre référence à la liste restera non filtrée.
Paul S

Ah, c'est vrai. Je me suis tellement attiré par la définition d'une méthode que j'ai négligé la simple tâche que vous aviez déjà faite.
Dannid

7

tu peux le faire

while 2 in x:   
    x.remove(2)

3
C'est une mauvaise solution, car la liste doit être parcourue 2 * n fois pour n occurrences de 2.
cxxl

Il n'est pas recommandé d'ajouter ou de supprimer de la liste que vous parcourez. Mauvaise pratique à mon humble avis.
Aman Mathur

5

Au détriment de la lisibilité, je pense que cette version est légèrement plus rapide car elle ne force pas le temps à réexaminer la liste, donc faire exactement le même travail que remove doit faire de toute façon:

x = [1, 2, 3, 4, 2, 2, 3]
def remove_values_from_list(the_list, val):
    for i in range(the_list.count(val)):
        the_list.remove(val)

remove_values_from_list(x, 2)

print(x)

Pour la liste que vous montrez dans votre code, cette approche est environ 36% plus lente que la méthode de compréhension de liste (qui renvoie une copie), selon ma mesure.
djsmith

Bon, vous l'avez remarqué. Cependant, parce que je pense que cela pourrait avoir dérapé votre jugement, je comparais ma version avec la toute première proposition faite par l'auteur de la question.
Martin Andersson

4

Approche Numpy et timings par rapport à une liste / tableau avec 1.000.000 éléments:

Calendrier:

In [10]: a.shape
Out[10]: (1000000,)

In [13]: len(lst)
Out[13]: 1000000

In [18]: %timeit a[a != 2]
100 loops, best of 3: 2.94 ms per loop

In [19]: %timeit [x for x in lst if x != 2]
10 loops, best of 3: 79.7 ms per loop

Conclusion: numpy est 27 fois plus rapide (sur mon cahier) que l'approche de compréhension de liste

PS si vous souhaitez convertir votre liste Python régulière lsten tableau numpy:

arr = np.array(lst)

Installer:

import numpy as np
a = np.random.randint(0, 1000, 10**6)

In [10]: a.shape
Out[10]: (1000000,)

In [12]: lst = a.tolist()

In [13]: len(lst)
Out[13]: 1000000

Vérifier:

In [14]: a[a != 2].shape
Out[14]: (998949,)

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949

4
a = [1, 2, 2, 3, 1]
to_remove = 1
a = [i for i in a if i != to_remove]
print(a)

Peut-être pas le plus pythonique mais toujours le plus facile pour moi haha


3

Pour supprimer toutes les occurrences en double et en laisser une dans la liste:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

Voici la fonction que j'ai utilisée pour Project Euler:

def removeOccurrences(e):
  return list(set(e))

2
J'avais besoin de le faire sur un vecteur avec des valeurs de 250k, et cela fonctionne comme un charme.
rschwieb

1
La réponse est oui! Et je comprends parfaitement si avoir un vecteur qui sonne longtemps complètement fou pour un programmeur compétent. J'aborde les problèmes là-bas en tant que mathématicien, sans me soucier d'optimiser les solutions, et cela peut conduire à des solutions plus longues que la normale. (Bien que je n'aie aucune patience pour les solutions de plus de 5 minutes.)
rschwieb

6
Cela supprimera toute commande de la liste.
asmeurer

4
@JaredBurrows peut-être parce qu'il ne répond pas à la question telle qu'elle est actuellement, mais à une question très différente.
drevicko

6
-1, ce n'est pas une réponse à la question du PO. C'est une solution pour supprimer les doublons, ce qui est complètement différent.
Anoyz

2

Je crois que c'est probablement plus rapide que toute autre façon si vous ne vous souciez pas de l'ordre des listes, si vous vous souciez de la commande finale, stockez les index de l'original et recourez à cela.

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]

2
Je comprends où vous allez, mais ce code ne fonctionnera pas car vous avez également besoin de l'index de démarrage et pas seulement de 0.
Shedokan

2
for i in range(a.count(' ')):
    a.remove(' ')

Je pense que c'est beaucoup plus simple.


2
veuillez modifier votre réponse afin d'améliorer la clarté. Veuillez indiquer clairement ce que fait exactement votre code recommandé, pourquoi il fonctionne et pourquoi c'est votre recommandation. Veuillez également formater correctement votre question afin que le code soit clairement perceptible dans le reste de votre réponse.
Ortund

2

Laisser

>>> x = [1, 2, 3, 4, 2, 2, 3]

La solution la plus simple et la plus efficace, comme déjà publiée précédemment, est

>>> x[:] = [v for v in x if v != 2]
>>> x
[1, 3, 4, 3]

Une autre possibilité qui devrait utiliser moins de mémoire mais être plus lente est

>>> for i in range(len(x) - 1, -1, -1):
        if x[i] == 2:
            x.pop(i)  # takes time ~ len(x) - i
>>> x
[1, 3, 4, 3]

Résultats de synchronisation pour les listes de longueur 1000 et 100000 avec 10% d'entrées correspondantes: 0,16 contre 0,25 ms et 23 contre 123 ms.

Timing avec longueur 1000

Timing avec longueur 100000


1

Supprimer toutes les occurrences d'une valeur d'une liste Python

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list():
    for list in lists:
      if(list!=7):
         print(list)
remove_values_from_list()

Résultat: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

Alternativement,

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list(remove):
    for list in lists:
      if(list!=remove):
        print(list)
remove_values_from_list(7)

Résultat: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


"Python 'imbriqué pour chaque boucle if' dans une fonction fonctionnant avec une précision de 100%!"
rafiqul786

Vous ne modifiez pas la liste, vous imprimez simplement les éléments. Nommer également une liste en tant que listes est source de confusion
kon psych

0

Si vous n'avez pas intégré filterou ne voulez pas utiliser d'espace supplémentaire et que vous avez besoin d'une solution linéaire ...

def remove_all(A, v):
    k = 0
    n = len(A)
    for i in range(n):
        if A[i] !=  v:
            A[k] = A[i]
            k += 1

    A = A[:k]

0
hello =  ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
#chech every item for a match
for item in range(len(hello)-1):
     if hello[item] == ' ': 
#if there is a match, rebuild the list with the list before the item + the list after the item
         hello = hello[:item] + hello [item + 1:]
print hello

['Bonjour le monde']


veuillez essayer d'élaborer votre réponse avec des explications.
parlad du

0

Je viens de le faire pour une liste. Je ne suis qu'un débutant. Un programmeur légèrement plus avancé peut sûrement écrire une fonction comme celle-ci.

for i in range(len(spam)):
    spam.remove('cat')
    if 'cat' not in spam:
         print('All instances of ' + 'cat ' + 'have been removed')
         break

0

Nous pouvons également supprimer sur place tous les éléments à l'aide de delou pop:

import random

def remove_values_from_list(lst, target):
    if type(lst) != list:
        return lst

    i = 0
    while i < len(lst):
        if lst[i] == target:
            lst.pop(i)  # length decreased by 1 already
        else:
            i += 1

    return lst

remove_values_from_list(None, 2)
remove_values_from_list([], 2)
remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)], 2)
print(len(lst))

Maintenant pour l'efficacité:

In [21]: %timeit -n1 -r1 x = random.randrange(0,10)
1 loop, best of 1: 43.5 us per loop

In [22]: %timeit -n1 -r1 lst = [random.randrange(0, 10) for x in range(1000000)]
g1 loop, best of 1: 660 ms per loop

In [23]: %timeit -n1 -r1 lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)]
    ...: , random.randrange(0,10))
1 loop, best of 1: 11.5 s per loop

In [27]: %timeit -n1 -r1 x = random.randrange(0,10); lst = [a for a in [random.randrange(0, 10) for x in
    ...:  range(1000000)] if x != a]
1 loop, best of 1: 710 ms per loop

Comme nous le voyons, la version sur place remove_values_from_list()ne nécessite aucune mémoire supplémentaire, mais son exécution prend beaucoup plus de temps:

  • 11 secondes pour les valeurs de suppression sur place
  • 710 milli secondes pour la compréhension des listes, qui alloue une nouvelle liste en mémoire

0

Personne n'a posté une réponse optimale pour la complexité du temps et de l'espace, alors j'ai pensé que je pourrais lui donner un coup de feu. Voici une solution qui supprime toutes les occurrences d'une valeur spécifique sans créer de nouveau tableau et à une complexité temporelle efficace. L'inconvénient est que les éléments ne maintiennent pas l' ordre .

Complexité temporelle: O (n)
Complexité d'espace supplémentaire: O (1)

def main():
    test_case([1, 2, 3, 4, 2, 2, 3], 2)     # [1, 3, 3, 4]
    test_case([3, 3, 3], 3)                 # []
    test_case([1, 1, 1], 3)                 # [1, 1, 1]


def test_case(test_val, remove_val):
    remove_element_in_place(test_val, remove_val)
    print(test_val)


def remove_element_in_place(my_list, remove_value):
    length_my_list = len(my_list)
    swap_idx = length_my_list - 1

    for idx in range(length_my_list - 1, -1, -1):
        if my_list[idx] == remove_value:
            my_list[idx], my_list[swap_idx] = my_list[swap_idx], my_list[idx]
            swap_idx -= 1

    for pop_idx in range(length_my_list - swap_idx - 1):
        my_list.pop() # O(1) operation


if __name__ == '__main__':
    main()

-1

À propos de la vitesse!

import time
s_time = time.time()

print 'start'
a = range(100000000)
del a[:]
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 3.25

s_time = time.time()
print 'start'
a = range(100000000)
a = []
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 2.11

-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

Uniquement avec Python 3


2
De manière hilarante, cela entre dans le cadre de la question posée et est correct.
Erich

Je ne vois pas comment c'est correct. Cela supprimera tous les éléments de la liste, pas toutes les occurrences d'une valeur .
Georgy

-3

Quel est le problème avec:

Motor=['1','2','2']
For i in Motor:
       If i  != '2':
       Print(i)
Print(motor)

Utiliser anaconda


2
Veuillez expliquer vos lignes de code afin que les autres utilisateurs puissent comprendre ses fonctionnalités. Merci!
Ignacio Ara

Ce code ne supprimera rien de la liste.
Georgy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.