Usunąć wszystkie wystąpienia wartości z listy?


377

W Python remove()usunie pierwsze wystąpienie wartości z listy.

Jak usunąć wszystkie wystąpienia wartości z listy?

Oto, co mam na myśli:

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

Odpowiedzi:


505

Podejście funkcjonalne:

Python 3.x

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

lub

>>> 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
Skorzystaj ze zrozumienia listy nad filtrem + lambda; ten pierwszy jest bardziej czytelny oprócz ogólnie bardziej wydajnego.
habnabit

17
s /
general

99
Kod sugestii habnabit wygląda następująco:[y for y in x if y != 2]
coredumperror

8
Nie nazwałbym tego rozwiązania najlepszym. Zrozumienie listy jest szybsze i łatwiejsze do zrozumienia podczas przeglądania kodu. Byłoby to raczej perlowe niż Python.
Peter Nimroot,

3
-1 do bezpośredniego wywoływania __ne__. Porównanie dwóch wartości jest procesem znacznie bardziej złożonym niż tylko wywołanie __eq__lub __ne__jedna z nich. Może tutaj działać poprawnie, ponieważ porównujesz tylko liczby, ale w ogólnym przypadku jest to niepoprawne i błąd.
Aran-Fey

211

Możesz użyć rozumienia listy:

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
Jak usunąłbyś elementy bez ich sprawdzania?
Alexander Ljungberg

18
To nie modyfikuje oryginalnej listy, ale zwraca nową listę.
John Y

6
@ Selinap: Nie, jest to optymalne, ponieważ skanuje listę tylko raz. W oryginalnym kodzie zarówno inoperator, jak i removemetoda skanują całą listę (aż do znalezienia dopasowania), dzięki czemu skanujesz listę wiele razy w ten sposób.
John Kugelman

4
@mhawke, @John Y: po prostu użyj x [:] = ... zamiast x = i będzie to „w miejscu”, a nie tylko ponowne wiązanie nazwy „x” (prędkość jest zasadniczo taka sama i DUŻO szybsza niż x .remove może być !!!).
Alex Martelli,

10
Głosuję za tym, ponieważ po 6 latach Python nadal nie rozumiem Lambdas :)
Benjamin

107

Możesz użyć przypisania wycinka, jeśli oryginalna lista musi zostać zmodyfikowana, przy jednoczesnym korzystaniu ze skutecznego rozumienia listy (lub wyrażenia generatora).

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

1
@ Selinap: filtr nie modyfikuje listy, zwraca nową listę.
EM

Filtr i wyrazy listy nie modyfikują listy. robi przypisanie plasterka. a oryginalny przykład tak.
A. Coady

7
Podoba mi się to, ponieważ modyfikuje listę, do której odnosi się x. Jeśli pojawią się jakieś inne odniesienia do tej listy, zostaną one również zmienione. Jest to sprzeczne z x = [ v for v in x if x != 2 ]propozycjami, które tworzą nową listę i zmieniają x, aby się do niej odwoływać, pozostawiając pierwotną listę nietkniętą.
Hannes,

40

Powtarzając rozwiązanie pierwszego postu w bardziej abstrakcyjny sposób:

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

19
Ale to O (n * n).
Hannes,

@ Hannes nie byłoby O (n), ponieważ przechodzi przez pętlę tylko raz i jednocześnie usuwa element?
penta

1
Zastanów się x = [1] * 10000 + [2] * 1000. Ciało pętli wykonuje się 1000 razy, a .remove () musi pomijać 10000 elementów przy każdym wywołaniu. Dla mnie to pachnie jak O (n * n), ale nie jest to dowodem. Myślę, że dowodem byłoby założenie, że liczba 2 na liście jest proporcjonalna do jej długości. Ten współczynnik proporcjonalności znika następnie w notacji big-O. Najlepszym jednak przypadkiem, gdy tylko stała liczba 2s na liście, nie jest O (n ^ 2), tylko O ​​(2n), które jest O (n).
Hannes,

23

Zobacz proste rozwiązanie

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

Zwróci to listę zawierającą wszystkie elementy xbez2


11

Wszystkie powyższe odpowiedzi (oprócz Martina Anderssona) tworzą nową listę bez żądanych elementów, zamiast usuwać elementy z oryginalnej listy.

>>> 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

Może to być ważne, jeśli masz inne odniesienia do listy.

Aby zmodyfikować listę na miejscu, użyj metody takiej jak ta

>>> 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

Jeśli chodzi o szybkość, wyniki na moim laptopie są (wszystkie na liście wpisów 5000 z usuniętymi 1000 wpisami)

  • Zrozumienie listy - ~ 400us
  • Filtr - ~ 900us
  • Pętla .remove () - 50ms

Więc pętla .remove jest około 100 razy wolniejsza ... Hmmm, być może potrzebne jest inne podejście. Najszybsze, jakie znalazłem, korzysta ze zrozumienia listy, ale następnie zastępuję zawartość oryginalnej listy.

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

Dlaczego więc nie przypisać nowej listy do starego adresu? def remove_all(x, l): return [y for y in l if y != x]następniel = remove_all(3,l)
Dannid

@Dannid To druga metoda w pierwszym polu kodu. Tworzy nową listę i nie modyfikujesz starej listy. Wszelkie inne odniesienia do listy pozostaną niefiltrowane.
Paul S

Ah, tak. Tak pochłonęło mnie definiowanie metody, że przeoczyłem proste zadanie, które już wykonałeś.
Dannid

7

możesz to zrobić

while 2 in x:   
    x.remove(2)

3
To złe rozwiązanie, ponieważ lista musi być przeglądana 2 * n razy dla n wystąpień 2.
cxxl,

Nie zaleca się dodawania ani usuwania z listy, którą przechodzisz. Zła praktyka IMHO.
Aman Mathur

5

Kosztem czytelności uważam, że ta wersja jest nieco szybsza, ponieważ nie zmusza do ponownego sprawdzenia listy, dlatego wykonanie dokładnie tej samej pracy, którą trzeba usunąć:

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)

W przypadku listy wyświetlanej w kodzie podejście to jest o około 36% wolniejsze niż metoda zrozumienia listy (która zwraca kopię), zgodnie z moim pomiarem.
djsmith,

Dobrze, że to zauważyłeś. Ponieważ jednak myślę, że mogło to umknąć twojej ocenie, porównałem moją wersję z pierwszą propozycją autora pytania.
Martin Andersson

4

Numpy podejście i czasy względem listy / tablicy z 1.000.000 elementów:

Czasy:

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

Wniosek: numpy jest 27 razy szybszy (w moim notatniku) w porównaniu do podejścia do listowania

PS, jeśli chcesz przekonwertować swoją zwykłą listę Python lstna tablicę numpy:

arr = np.array(lst)

Ustawiać:

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

Czek:

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)

Być może nie najbardziej pytoniczny, ale wciąż najłatwiejszy dla mnie haha


3

Aby usunąć wszystkie zduplikowane wystąpienia i pozostawić je na liście:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

Oto funkcja, której użyłem w Project Euler:

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

2
Musiałem to zrobić na wektorze o wartości 250k i działa to jak urok.
rschwieb

1
Odpowiedź brzmi tak! I całkowicie rozumiem, czy posiadanie wektora, który długo brzmi kompletnie szalenie dla kompetentnego programisty. Podchodzę do problemów tam jako matematyk, nie martwiąc się o optymalizację rozwiązań, a to może prowadzić do rozwiązań dłuższych niż norma. (Chociaż nie mam cierpliwości do rozwiązań dłuższych niż 5 minut.)
rschwieb

6
Spowoduje to usunięcie dowolnego zamówienia z listy.
asmeurer

4
@JaredBurrows być może dlatego, że nie odpowiada na obecne pytanie, ale na zupełnie inne pytanie.
drevicko

6
-1, to nie jest odpowiedź na pytanie PO. Jest to rozwiązanie do usuwania duplikatów, co jest zupełnie inną sprawą.
Anoyz

2

Uważam, że jest to prawdopodobnie szybsze niż jakikolwiek inny sposób, jeśli nie przejmujesz się kolejnością list, jeśli dbasz o ostateczne zamówienie, zapisz indeksy z oryginału i skorzystaj z niego.

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

2
Rozumiem, dokąd zmierzasz, ale ten kod nie będzie działał, ponieważ potrzebujesz również indeksu początkowego, a nie tylko 0.
Shedokan 27.04.13

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

O wiele łatwiejsze.


2
edytuj swoją odpowiedź, aby poprawić jasność. Wyjaśnij dokładnie, co dokładnie robi Twój zalecany kod, dlaczego działa i dlaczego jest to twoja rekomendacja. Proszę również poprawnie sformatować pytanie, aby kod był wyraźnie widoczny z pozostałej części odpowiedzi.
Ortund

2

Pozwolić

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

Najprostszym i wydajnym rozwiązaniem, jak już wcześniej napisano, jest

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

Inną możliwością, która powinna zużywać mniej pamięci, ale być wolniejsza, jest

>>> 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]

Wyniki pomiaru czasu dla list o długości 1000 i 100000 z 10% pasującymi wpisami: 0,16 vs 0,25 ms i 23 vs 123 ms.

Czas o długości 1000

Czas o długości 100000


1

Usuń wszystkie wystąpienia wartości z listy 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()

Wynik: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

Alternatywnie,

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)

Wynik: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


„Python” zagnieżdżony dla każdej pętli if w funkcji działającej ze 100% dokładnością! ”
rafiqul786

Nie modyfikujesz listy, po prostu drukujesz elementy. Mylące jest także nazywanie listy jako listy
kon psych

0

Jeśli nie masz wbudowanej filterlub nie chcesz używać dodatkowej przestrzeni i potrzebujesz rozwiązania liniowego ...

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

['Witaj świecie']


spróbuj opracować swoją odpowiedź wraz z wyjaśnieniem.
paczka

0

Zrobiłem to tylko dla listy. Jestem tylko początkującym. Nieco bardziej zaawansowany programista z pewnością może napisać taką funkcję.

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

0

Możemy również usunąć wszystkie na miejscu za pomocą jednego dellub dwóch 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))

Teraz wydajność:

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

Jak widzimy, wersja remove_values_from_list()lokalna nie wymaga dodatkowej pamięci, ale jej uruchomienie zajmuje znacznie więcej czasu:

  • 11 sekund na miejsce usuń wartości
  • 710 milisekund na zrozumienie listy, która przydziela nową listę w pamięci

0

Nikt nie opublikował optymalnej odpowiedzi na złożoność czasu i przestrzeni, więc pomyślałem, że dam jej szansę. Oto rozwiązanie, które usuwa wszystkie wystąpienia określonej wartości bez tworzenia nowej tablicy i przy złożonym czasie. Wadą jest to, że elementy nie utrzymują porządku .

Złożoność czasowa: O (n)
Dodatkowa złożoność przestrzeni: 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

O prędkości!

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)
[]

Tylko z Python 3


2
Zabawne, że jest to objęte zadanym pytaniem i jest prawidłowe.
Erich

Nie rozumiem, jak to jest poprawne. Spowoduje to usunięcie wszystkich pozycji z listy, a nie wszystkich wystąpień wartości .
Georgy

-3

Co jest źle z:

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

Korzystanie z anakondy


2
Wyjaśnij swoje linie kodu, aby inni użytkownicy mogli zrozumieć jego funkcjonalność. Dzięki!
Ignacio Ara,

Ten kod niczego nie usunie z listy.
Georgy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.