2011-02-10 10 views
5

I loop attraverso un elenco e rimuovere gli elementi che soddisfano la mia condizione. Ma perché non funziona, come indicato di seguito? Grazie.come rimuovere in modo sicuro gli elementi da un elenco in Python

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

risposta

9

Non è possibile modificare qualcosa mentre lo si sta iterando. I risultati sono strani e contro-intuitivi e quasi mai ciò che desideri. In effetti, molte raccolte non consentono esplicitamente questo (ad es. Insiemi e dict).

Invece, scorrere su una copia (for e in a[:]: ...) oppure, invece di modificare un elenco esistente, filtrarlo per ottenere un nuovo elenco contenente gli elementi desiderati ([e for e in a if ...]). Si noti che in molti casi non è necessario ripetere nuovamente l'iterazione per filtrare, basta unire il filtro con la generazione dei dati.

5

Perché non basta fare questo inizialmente nella lista di comprensione? Per esempio.

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

Puoi anche usarlo per costruire un nuovo elenco dall'elenco esistente, ad es.

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

Restituisce gli articoli che dovrebbero essere effettivamente rimossi. –

+0

@ Spiacente, lo aggiusterò –

1

Non è sicuro rimuovere gli elementi da un elenco mentre lo itera. Perché esiste la funzione filtro. Prende una funzione (che ammette un argomento) e una iterabile (in questo caso la tua lista). Esso restituisce un nuovo iterabile dello stesso tipo (lista di nuovo qui) con gli elementi in cui la funzione applicata a quell'elemento restituito true:

Nel tuo caso è possibile utilizzare una funzione lambda come questo:

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

o se avete la lista già:

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

ricordare che se si sta utilizzando python3 restituirà un iteratore e non una lista.

+0

Per casi semplici come questo, preferirei una comprensione di lista su 'filtro'. –

2

L'idea del filtro è buona, tuttavia manca il punto che è che alcune liste possono essere molto grandi e il numero di elementi da rimuovere può essere molto piccolo.

In tal caso, la risposta è ricordare gli indici di elenco degli elementi da rimuovere e quindi scorrere l'elenco di indici, ordinati dal più grande al più piccolo, rimuovendo gli elementi.

+0

Supponiamo che tu abbia un elenco di 1 milione di elementi e 4 rimossi. Filtrarlo significa mischiare circa 1.000.000 di elementi, mentre il tuo suggerimento implicherebbe una media di circa il doppio rispetto a quelli in media. Ovviamente altri fattori significheranno che non è così semplice, ma a meno che tu non abbia effettivamente programmato il codice, direi che rimani con il più semplice (filtraggio) in quanto non otterrai molto, semmai, rendendolo più complesso. – Duncan

+0

Non prenderei in considerazione la ricerca di elementi da "mischiare". E alla fine, hai una lista di 4 elementi che tu fai scorrere in ordine inverso, e le cancellazioni comportano lo scollegamento degli elementi dell'elenco, quindi, di nuovo, dov'è lo shuffle? –

2

Il modo più semplice per visualizzarlo consiste nel pensare all'iterazione che agisce sugli elenchi di offset anziché sugli oggetti effettivi: fare qualcosa per il primo elemento, quindi il secondo elemento, quindi il terzo elemento, finché non esaurisce gli elementi . Se si modifica il numero di elementi nella lista, cambia gli offset di tutti gli altri elementi della lista:

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

risultati in

1 
4 
[1,3,4] 

che ha un senso se fate un passo attraverso di essa in questo modo :

[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 

l'unica vera soluzione è non modificare il numero di elementi nella lista, mentre si sta iterando su di esso. Copia gli elementi che desideri conservare in un nuovo elenco o tieni traccia dei valori che desideri rimuovere e rimuovi il valore per valore in un passaggio separato.

+0

+1 per spiegare i dettagli cattivi. – delnan

Problemi correlati