Czy istnieje prosty sposób na usunięcie elementu listy według wartości?


942
a = [1, 2, 3, 4]
b = a.index(6)

del a[b]
print(a)

Powyżej pokazuje następujący błąd:

Traceback (most recent call last):
  File "D:\zjm_code\a.py", line 6, in <module>
    b = a.index(6)
ValueError: list.index(x): x not in list

Więc muszę to zrobić:

a = [1, 2, 3, 4]

try:
    b = a.index(6)
    del a[b]
except:
    pass

print(a)

Ale czy nie ma prostszego sposobu na zrobienie tego?


14
Obliczasz indeks 6 na swojej liście. Ale 6 nie ma na twojej liście ... więc co się stanie? :)
Johannes Charra

5
nie ma to nic wspólnego z usuwaniem wartości z listy, ponieważ kod nie osiąga instrukcji del. Może powinieneś zmienić nazwę „jak uzyskać indeks wartości, której nie ma na liście. Oczywista odpowiedź - nie możesz.”
Dave Kirby

57
@Dave Cóż, niezupełnie. Chce usunąć element z listy, niezależnie od tego, czy istnieje, czy nie, aby nie uzyskać indeksu dla nieistniejącego elementu. Pytanie jest dobrze zadane.
ibz

Poza tym, ale gołe exceptto zła praktyka . Używaj except Exceptionco najmniej.
wjandrea

Odpowiedzi:


1563

Aby usunąć pierwsze wystąpienie elementu z listy, po prostu użyj list.remove:

>>> a = ['a', 'b', 'c', 'd']
>>> a.remove('b')
>>> print(a)
['a', 'c', 'd']

Pamiętaj, że nie usuwa wszystkich wystąpień twojego elementu. Użyj do tego zrozumienia listy.

>>> a = [10, 20, 30, 40, 20, 30, 40, 20, 70, 20]
>>> a = [x for x in a if x != 20]
>>> print(a)
[10, 30, 40, 30, 40, 70]

144
Nie działa, jeśli elementu nie ma na liście. :)
ibz

21
Czytanie listy @ibz nie kończy się niepowodzeniem, nawet jeśli elementu nie ma na liście, prawda?
Izaak

76
Aby wyjaśnić każdemu przeglądanie, „nie działa” w tym sensie, że wywołuje wyjątek ValueError.
Casey Falk

10
Zrozumienie listy zmienia odwołanie do listy, więc jeśli gdzieś jest kopia odwołania, usunięcie nie nastąpi.
Sebastien

Jaka jest złożoność tego, removeże O (n)?
Rasmi Ranjan Nayak

184

Zwykle Python zgłasza wyjątek, jeśli powiesz mu, aby zrobił coś, czego nie może, więc będziesz musiał zrobić albo:

if c in a:
    a.remove(c)

lub:

try:
    a.remove(c)
except ValueError:
    pass

Wyjątek niekoniecznie musi być złą rzeczą, o ile oczekuje się tego i odpowiednio się z nim obchodzi.


9
Lepiej jest zapobiegać niż leczyć. Jeśli możesz najpierw sprawdzić wyjątkowe warunki (przykład a), powinieneś.
Gusdor

82
Chociaż dotyczy to innych języków, w Pythonie „łatwiej jest prosić o wybaczenie niż o pozwolenie”. docs.python.org/2/glossary.html#term-eafp
Dave Webb

6
@Gusdor: jeśli lista jest współdzielona między wątkami, a.remove(c)mimo to może się nie powieść pomimo if c in asprawdzenia ( amoże zostać zmodyfikowany w innym wątku po c in asprawdzeniu, ale przed a.remove(c)wywołaniem). try/exceptlub można zastosować zamki, aby uniknąć wyścigu.
jfs

7
@JFSebastian, jeśli lista jest udostępniana między wątkami i nie stosujesz sekcji krytycznych, masz większe problemy.
Gusdor

4
@Gusdor, idiom Pythonique ma spróbować bez sprawdzania i wychwycić wyjątek, jeśli wystąpi. Jest bardziej wydajny (tylko jedno wyszukiwanie zamiast dwóch), choć trochę brzydszy
Jeet

80

Możesz to zrobić

a=[1,2,3,4]
if 6 in a:
    a.remove(6)

ale powyżej trzeba przeszukać 2 na liście 2 razy, więc spróbuj z wyjątkiem, że byłoby szybsze

try:
    a.remove(6)
except:
    pass

55

Rozważać:

a = [1,2,2,3,4,5]

Aby usunąć wszystkie wystąpienia, możesz użyć funkcji filtrowania w Pythonie. Na przykład wyglądałoby to tak:

a = list(filter(lambda x: x!= 2, a))

Zachowałoby to wszystkie elementy a != 2.

Aby wyjąć jeden z przedmiotów, użyj

a.remove(2)

Dlaczego pakujesz filter()w inny list()? Zgodnie z instrukcją zwraca już listę.
Olaf Dietsche,

8
@OlafDietsche W Pythonie 3.x zwraca obiekt filtru (w 2.x zwraca listę), więc muszę rzucić „a” na listę, aby mieć jakąkolwiek funkcjonalność.
mathwizurd,

17

Oto jak to zrobić w miejscu (bez zrozumienia listy):

def remove_all(seq, value):
    pos = 0
    for item in seq:
        if item != value:
           seq[pos] = item
           pos += 1
    del seq[pos:]

Bardzo sprytne - naprawdę to lubię - niestety wydaje się tak nieefektywne jak najpopularniejsza odpowiedź. Rozwiązanie gila jest w rzeczywistości znacznie szybsze dla gigantycznych list z zaledwie kilkoma wystąpieniami wartości, którą chcesz usunąć.
Larold,

1
@ Larold Najszybszym sposobem byłoby osobne pytanie. Moje pieniądze znajdują się na liście w ogólnym przypadku. To rozwiązanie powinno działać naprawdę dobrze, jeśli wartość jest częsta na liście danych wejściowych i nie jest używane rozumienie listy. Wypróbuj Pypy, numpy data w Cython. [Odpowiedź Gilla jest O(n*n)niepotrzebna (porównaj 1e6 i 1e12 - nie chcesz ryzykować tego drugiego). while 1: L.remove(value)i powrót ValueErrormoże działać dobrze z kilkoma values lub małymi listami w CPython.
jfs

13

Jeśli wiesz, jaką wartość usunąć, oto prosty sposób (w każdym razie tak prosty, jak tylko mogę sobie wyobrazić):

a = [0, 1, 1, 0, 1, 2, 1, 3, 1, 4]
while a.count(1) > 0:
    a.remove(1)

Dostaniesz [0, 0, 2, 3, 4]


4
Dlaczego nie użyć while 1 in a:jako struktury pętli?
TerminalDilettante

12
Właśnie O(n^2)tam byłoby zrozumienie O(n).
Mad Physicist

1
Oczywiście @MadPhysicist ma rację, a wersja TerminalDilettante jest znacznie bardziej pytoniczna, nawet jeśli nie zależy nam na wydajności. W 2013 roku zacząłem uczyć się języka Python, a obecnie dość często wstydzę się tego, co wtedy napisałem.
gil

11

Inną możliwością jest użycie zestawu zamiast listy, jeśli zestaw ma zastosowanie w Twojej aplikacji.

IE, jeśli twoje dane nie są uporządkowane i nie mają duplikatów, to

my_set=set([3,4,2])
my_set.discard(1)

jest wolny od błędów.

Często lista jest po prostu poręcznym pojemnikiem na przedmioty, które są faktycznie nieuporządkowane. Pojawiają się pytania dotyczące usuwania wszystkich wystąpień elementu z listy. Jeśli nie chcesz dupków, po raz kolejny przydatny jest zestaw.

my_set.add(3)

nie zmienia my_set z góry.


10

Jak stwierdzono w wielu innych odpowiedziach, list.remove()zadziała, ale rzuć a, ValueErrorjeśli pozycji nie było na liście. W Pythonie 3.4+ istnieje ciekawe podejście do radzenia sobie z tym przy użyciu menedżera kontekstu pomijania :

from contextlib import suppress
with suppress(ValueError):
    a.remove('b')

8

Znalezienie wartości na liście, a następnie usunięcie tego indeksu (jeśli istnieje) jest łatwiejsze dzięki użyciu metody usuwania listy:

>>> a = [1, 2, 3, 4]
>>> try:
...   a.remove(6)
... except ValueError:
...   pass
... 
>>> print a
[1, 2, 3, 4]
>>> try:
...   a.remove(3)
... except ValueError:
...   pass
... 
>>> print a
[1, 2, 4]

Jeśli robisz to często, możesz zawinąć to w funkcję:

def remove_if_exists(L, value):
  try:
    L.remove(value)
  except ValueError:
    pass

8

Ten przykład jest szybki i usunie wszystkie wystąpienia wartości z listy:

a = [1,2,3,1,2,3,4]
while True:
    try:
        a.remove(3)
    except:
        break
print a
>>> [1, 2, 1, 2, 4]

2
jeśli to zrobisz powinieneś naprawdę tylko breakon except ValueError.
Anthon

8

W jednej linii:

a.remove('b') if 'b' in a else None

czasami jest to przydatne.

Jeszcze łatwiej:

if 'b' in a: a.remove('b')

7

Jeśli twoje elementy są wyraźne, wystarczy prosta różnica w zestawie.

c = [1,2,3,4,'x',8,6,7,'x',9,'x']
z = list(set(c) - set(['x']))
print z
[1, 2, 3, 4, 6, 7, 8, 9]

2
Jeśli twoje elementy są wyraźne i nie obchodzi cię porządek .
Tom Zych,

2

Możemy również użyć .pop:

>>> lst = [23,34,54,45]
>>> remove_element = 23
>>> if remove_element in lst:
...     lst.pop(lst.index(remove_element))
... 
23
>>> lst
[34, 54, 45]
>>> 

2

Zastąp listę, indeksując wszystko oprócz elementów, które chcesz usunąć

>>> s = [5,4,3,2,1]
>>> s[0:2] + s[3:]
[5, 4, 2, 1]

2

Z pętlą for i warunkiem:

def cleaner(seq, value):    
    temp = []                      
    for number in seq:
        if number != value:
            temp.append(number)
    return temp

A jeśli chcesz usunąć niektóre, ale nie wszystkie:

def cleaner(seq, value, occ):
    temp = []
    for number in seq:
        if number == value and occ:
            occ -= 1
            continue
        else:
            temp.append(number)
    return temp

1
 list1=[1,2,3,3,4,5,6,1,3,4,5]
 n=int(input('enter  number'))
 while n in list1:
    list1.remove(n)
 print(list1)

Bez użycia funkcji filtrowania
Ravikiran D

1

Powiedzmy na przykład, że chcemy usunąć wszystkie 1 z x. Tak bym to zrobił:

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

To praktyczne zastosowanie mojej metody:

def Function(List, Unwanted):
    [List.remove(Unwanted) for Item in range(List.count(Unwanted))]
    return List
x = Function(x, 1)
print(x)

A to moja metoda w jednym wierszu:

[x.remove(1) for Item in range(x.count(1))]
print(x)

Oba dają to jako wynik:

[2, 3, 2, 3, 2, 3]

Mam nadzieję że to pomoże. PS, proszę zauważyć, że zostało to napisane w wersji 3.6.2, więc może być konieczne dostosowanie go do starszych wersji.


1

Być może twoje rozwiązania działają z ints, ale nie działa dla mnie ze słownikami.

Z jednej strony remove () nie działało dla mnie. Ale może działa z podstawowymi typami. Sądzę, że poniższy kod to także sposób na usunięcie elementów z listy obiektów.

Z drugiej strony „del” również nie działało poprawnie. W moim przypadku, używając Pythona 3.6: kiedy próbuję usunąć element z listy w poleceniu „for” bucle za pomocą polecenia „del”, python zmienia indeks procesu i jądro zatrzymuje się przedwcześnie. Działa tylko wtedy, gdy usuniesz element po elemencie w odwrotnej kolejności. W ten sposób nie zmieniasz indeksu tablicy oczekujących elementów podczas jego przeglądania

Następnie użyłem:

c = len(list)-1
for element in (reversed(list)):
    if condition(element):
        del list[c]
    c -= 1
print(list)

gdzie „lista” jest jak [{'klucz1': wartość1 '}, {' klucz2 ': wartość2}, {' klucz3 ': wartość3}, ...]

Możesz także zrobić więcej Pythona za pomocą wyliczenia:

for i, element in enumerate(reversed(list)):
    if condition(element):
        del list[(i+1)*-1]
print(list)

0
arr = [1, 1, 3, 4, 5, 2, 4, 3]

# to remove first occurence of that element, suppose 3 in this example
arr.remove(3)

# to remove all occurences of that element, again suppose 3
# use something called list comprehension
new_arr = [element for element in arr if element!=3]

# if you want to delete a position use "pop" function, suppose 
# position 4 
# the pop function also returns a value
removed_element = arr.pop(4)

# u can also use "del" to delete a position
del arr[4]

0

To usuwa wszystkie wystąpienia "-v"z tablicy sys.argvi nie narzeka, jeśli nie znaleziono żadnych wystąpień:

while "-v" in sys.argv:
    sys.argv.remove('-v')

Możesz zobaczyć kod w akcji w pliku o nazwie speechToText.py:

$ python speechToText.py -v
['speechToText.py']

$ python speechToText.py -x
['speechToText.py', '-x']

$ python speechToText.py -v -v
['speechToText.py']

$ python speechToText.py -v -v -x
['speechToText.py', '-x']

-1

to moja odpowiedź, po prostu użyj na czas i dla

def remove_all(data, value):
    i = j = 0
    while j < len(data):
        if data[j] == value:
            j += 1
            continue
        data[i] = data[j]
        i += 1
        j += 1
    for x in range(j - i):
        data.pop()
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.