2011-02-10 13 views
5

Przeszukuję listę i usuwam elementy, które spełniają mój warunek. Ale dlaczego to nie działa, jak wspomniano poniżej? Dziękuję Ci.Jak bezpiecznie usunąć elementy z listy w Pythonie

>>> a=[ i for i in range(4)] 
>>> a 
[0, 1, 2, 3] 
>>> for e in a: 
...  if (e > 1) and (e < 4): 
...   a.remove(e) 
... 
>>> a 
[0, 1, 3] 
>>> a=[ i for i in range(4)] 
>>> for e in a: 
...  if (e > -1) and (e < 3): 
...   a.remove(e) 
... 
>>> a 
[1, 3] 

Odpowiedz

9

Nie można zmienić czegoś podczas iteracji. Rezultaty są dziwne i sprzeczne z intuicją, a prawie nigdy nie są zgodne z oczekiwaniami. W rzeczywistości wiele kolekcji wyraźnie tego nie akceptuje (np. Zestawy i dyktety).

Zamiast tego należy powtórzyć kopię (for e in a[:]: ...) lub zamiast modyfikować istniejącą listę, odfiltruj ją, aby uzyskać nową listę zawierającą żądane elementy ([e for e in a if ...]). Zauważ, że w wielu przypadkach nie musisz ponownie wykonywać iteracji, aby filtrować, wystarczy połączyć filtrowanie z generowaniem danych.

5

Dlaczego po prostu nie zrobisz tego na początku ze zrozumieniem listy? Na przykład.

[i for i in range(4) if i <= 1 or i >= 4] 

Można go również użyć do skonstruowania nowej listy z istniejącej listy, np.

[x for x in a if x <= 1 or x >= 4] 
+0

Powoduje zwrócenie elementów, które powinny zostać usunięte. –

+0

@Sven sorry, naprawię to –

1

Usunięcie elementów z listy podczas iteracji nie jest bezpieczne. W tym celu istnieje funkcja filtra. Przyjmuje funkcję (która dopuszcza jeden argument) i iterację (w tym przypadku twoją listę). Zwraca nowy iterable tego samego typu (listę ponownie tutaj) z elementami gdzie funkcja stosowana do tego elementu zwróconych prawda:

W twoim przypadku można użyć funkcji lambda tak:

a = filter(lambda x: x > 1 and x < 4, range(4)) 

lub jeśli masz już listę:

a = range(4) 
a = filter(lambda x: x > 1 and x < 4, a) 

Pamiętaj, że jeśli używasz python3, zwróci on iterator, a nie listę.

+0

W prostych przypadkach, takich jak ten, wolałbym zrozumienie listy przez 'filter'. –

2

Pomysł filtrowania jest dobry, jednak nie trafia do punktu, w którym niektóre listy mogą być bardzo duże, a liczba elementów do usunięcia może być bardzo mała.

W takim przypadku odpowiedzią jest zapamiętanie indeksów listy elementów do usunięcia, a następnie powtórzenie listy indeksów, posortowanych od największej do najmniejszej, usunięcie elementów.

+0

Powiedz, że masz 1 milion list elementów, a 4 zostały usunięte. Filtrowanie oznacza tasowanie około 1 000 000 elementów, podczas gdy twoja sugestia wymaga przeciętnego tasowania około dwa razy więcej. Oczywiście inne czynniki będą oznaczać, że nie jest to takie proste, ale jeśli nie masz tak naprawdę czasu na kod, powiedziałbym, że trzymam się najprostszego (filtrowania), ponieważ nie zyskasz wiele, jeśli cokolwiek, czyniąc go bardziej złożony. – Duncan

+0

Nie rozważałbym znalezienia elementów do "tasowania". I na końcu masz listę 4 elementów, które wykonujesz iteracyjnie w odwrotnej kolejności, a usuwanie obejmuje rozłączanie elementów listy, więc znowu, gdzie jest przetasowanie? –

2

Najprostszym sposobem wizualizacji jest myślenie o iteracji działającej na przesunięciach list zamiast rzeczywistych elementów - zrób coś dla pierwszego elementu, następnie drugiego elementu, a następnie trzeciego elementu, dopóki nie zabraknie elementów . W przypadku zmiany liczby elementów na liście, zmienia przesunięcia wszystkich pozostałych elementów w liście:

lst = [1,2,3,4] 
for item in lst: 
    if item==2: 
     lst.remove(item) 
    else: 
     print item 
print lst 

wyników w

1 
4 
[1,3,4] 

co ma sens, jeśli przejść przez niego jak tak :

[1,2,3,4] 
^ 
first item is not 2, so print it -> 1 

[1,2,3,4] 
^
    second item is 2, so remove it 

[1,3,4] 
    ^
    third item is 4, so print it -> 4 

jedynym rozwiązaniem jest nie zmienić liczbę pozycji na liście podczas iteracji nad nim. Skopiuj elementy, które chcesz zachować, do nowej listy lub śledź wartości, które chcesz usunąć, i usuń wartość według wartości w oddzielnym przebiegu.

+0

+1 za wyjaśnienie nieprzyjemnych szczegółów. – delnan

Powiązane problemy