2011-12-17 14 views
8

ciò di cui ho fondamentalmente bisogno è controllare ogni elemento di una lista e se alcuni criteri si adattano voglio rimuoverlo dalla lista.come modificare correttamente l'iteratore di un loop in python dall'interno del loop

Così, per esempio diciamo che

list = [ 'a', 'b', 'c', 'd', 'e']

Io fondamentalmente voglio scrivere (in linea di principio e non il codice effettivo che cerco di implementare)

Se un elemento della lista è 'b' o 'c' rimuovilo dall'elenco e prendi quello successivo.

Ma

for s in list: 
    if s=='b' or s=='c': 
     list.remove(s) 

riesce perché quando 'b' è rimosso l'anello assume 'd' e non 'c' come elemento successivo. Quindi c'è un modo per farlo più veloce di memorizzare gli elementi in un elenco separato e rimuoverli in seguito?

Grazie.

risposta

9

Il modo più semplice è quello di utilizzare una copia della lista - si può fare con una fetta che si estende "dal principio" per la "fine" della lista, in questo modo:

for s in list[:]: 
    if s=='b' or s=='c': 
     list.remove(s) 

È ho considerato questo, e questo è abbastanza semplice da essere nel tuo codice, a meno che questa lista non sia veramente grande, e in una parte critica del codice (come nel ciclo principale di un gioco d'azione). In tal caso, a volte uso il seguente idioma:

to_remove = [] 
for index, s in enumerate(list): 
    if s == "b" or s == "c": 
     to_remove.append(index) 

for index in reversed(to_remove): 
    del list[index] 

Naturalmente si può ricorrere a un ciclo while, invece:

index = 0 
while index < len(list): 
    if s == "b" or s == "c": 
     del list[index] 
     continue 
    index += 1 
+0

jsbueno vi ringrazio molto. Mi vergogno un po 'per non averlo pensato. Grazie ancora! – tst

+0

In realtà volevo un ciclo all'interno di un ciclo e il tuo ultimo esempio era perfetto. grazie ancora. – tst

1

se siete ok con la creazione di una copia della lista che si può fare in questo modo (list comprehension):

[s for s in list if s != 'b' and s != 'c'] 
8

il suo meglio per non reinventare le cose che sono già disponibili. Utilizzare le funzioni filter e lambda in questi casi. È più pitonico e sembra più pulito.

filter(lambda x:x not in ['b','c'],['a','b','c','d','e']) 

alternativa è possibile utilizzare di lista

[x for x in ['a','b','c','d','e'] if x not in ['b','c']] 
+0

In realtà, la comprensione delle liste nel tuo secondo esempio è "più Pythonic" rispetto alla combinazione di filtro e lambda. – jsbueno

+0

grazie, ma avevo bisogno di mettere uno di questi loop in un altro e in questo modo le cose possono diventare davvero disordinate. – tst

3

Questo è esattamente ciò che è stato progettato per itertools.ifilter.

from itertools import ifilter 

ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e']) 

restituirà un generatore per l'elenco. Se realmente bisogno di un elenco, è possibile crearla utilizzando uno dei tecniche standard per la conversione di un generatore a un elenco:

list(ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])) 

o

[x for x in ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])]