2010-03-25 19 views

risposta

86
>>> a = range(1, 10) 
>>> [x for x in a if x not in [2, 3, 7]] 
[1, 4, 5, 6, 8, 9] 
+7

Cosa succede se ho una lista '[1,2,2,2,3,4]' e una sottolista '[2,3]', quindi il risultato dovrebbe essere '[1,2,2,4 ] ', esiste un modo Python per farlo? – user

+0

@user questo ti dà la maggior parte del modo lì - ma il tuo problema è un altro problema! l = [1,2,2,3,4] sl = [2,3] [x per x in [l [n: n + 2] per n nell'intervallo (0, len (l)) [ :: 2]] se x! = Sl] – jsh

11
a = range(1,10) 
itemsToRemove = set([2, 3, 7]) 
b = filter(lambda x: x not in itemsToRemove, a) 

o

b = [x for x in a if x not in itemsToRemove] 

Non creare il set all'interno del lambda o all'interno la comprensione. Se lo fai, verrà ricreato ad ogni iterazione, annullando il punto di utilizzo di un set.

+1

Tranne che crea N set, N essendo len (a). – FogleBird

+0

Crea un solo set alla creazione della funzione lambda –

+0

Good point, FogleBird. Hai bisogno di crearlo al di fuori di lambda o della lista di comprensione. – Yaroslav

5

Altri hanno suggerito modi per creare una nuova lista dopo il filtraggio, ad es.

newl = [x for x in l if x not in [2,3,7]] 

o

newl = filter(lambda x: x not in [2,3,7], l) 

ma dalla tua domanda sembra che si desidera sul posto di modifica per che si può fare questo, questo sarà anche molto molto più veloce se l'elenco originale è lungo e articoli essere rimosso meno

l = range(1,10) 
for o in set([2,3,7,11]): 
    try: 
     l.remove(o) 
    except ValueError: 
     pass 

print l 

uscita: [1, 4, 5, 6, 8, 9]

Sto verificando l'eccezione ValueError in modo che funzioni anche se gli elementi non sono nella lista originale.

Anche se non è necessaria la soluzione di modifica sul posto da S.Mark è più semplice.

+0

se hai davvero bisogno di modifiche sul posto, le risposte precedenti possono essere modificate in: 'a [:] = [x per x in a se x non in [2,3,7]]'. Questo sarà più veloce del tuo codice. –

+2

sì a [:] può essere usato, ma non è ovvio che sarà più veloce, per le lunghe liste con pochi valori per rimuovere il mio codice sarà molto più veloce, ad es. prova la lista per rimuovere = [1] :) –

+0

@ Anurag: Sembri avere ragione; i test di temporizzazione fanno sembrare che la rimozione sul posto sia più veloce. –

5

Il modo più semplice è

>>> a = range(1, 10) 
>>> for x in [2, 3, 7]: 
... a.remove(x) 
... 
>>> a 
[1, 4, 5, 6, 8, 9] 

Un possibile problema è che ogni volta che si chiama rimuovere(), tutti gli elementi vengono mescolate l'elenco per riempire il buco. Quindi se lo a diventa molto grande, questo si rivelerà piuttosto lento.

In questo modo si crea una lista completamente nuova. Il vantaggio è che evitiamo tutto il rimescolamento del primo approccio

>>> removeset = set([2, 3, 7]) 
>>> a = [x for x in a if x not in removeset] 

Se si desidera modificare a a posto, solo un piccolo cambiamento è richiesto

>>> removeset = set([2, 3, 7]) 
>>> a[:] = [x for x in a if x not in removeset] 
+0

@gnibbler, la tua richiesta * "Quindi se' a' diventa molto grande questo finirà per essere piuttosto lento. "* È un po 'fuorviante. Se solo la lunghezza di 'a' è illimitata, tutti i frammenti che hai fornito sono O (n). Il ** problema ** reale con 'remove' è che rimuove solo * la prima occorrenza * dei suoi argomenti, non tutte le occorrenze. Inoltre, è generalmente più in linea con la scrittura di codice chiaro e idiomatico per creare una nuova lista piuttosto che mutare quella vecchia. –

+0

@Mike, ho cercato di mantenere la risposta semplice in quanto l'OP ha utilizzato il tag beginner. –

+3

"semplice" non è una scusa per * errato *. –

4
>>> a=range(1,10) 
>>> for i in [2,3,7]: a.remove(i) 
... 
>>> a 
[1, 4, 5, 6, 8, 9] 

>>> a=range(1,10) 
>>> b=map(a.remove,[2,3,7]) 
>>> a 
[1, 4, 5, 6, 8, 9] 
+0

Non utilizzare 'map' per gli effetti collaterali. 'map' è per raccogliere il risultato di un gruppo di chiamate. I loop sono lo strumento per fare qualcosa un po 'di volte. –

+0

se ciò che intendi per effetti collaterali sono quelli "nessuno" restituito da 'mappa', quindi può essere" mascherato ". A parte questo, è ancora valido, e mi piace la sua concisione. – ghostdog74

29

Se non lo fai avere valori ripetuti, è possibile utilizzare la differenza di set.

x = set(range(10)) 
y = x - set([2, 3, 7]) 
# y = set([0, 1, 4, 5, 6, 8, 9]) 

e quindi riconvertire in elenco, se necessario.

+0

Nota che questo rimescola l'elenco risultante. –

+1

L'ordine della lista può cambiare, ma in modo deterministico. Non è "mescolato" nel senso casuale. – dansalmo

+3

inoltre, se l'elenco originale x ha duplicati, dopo l'operazione set(), viene salvato solo uno. –

14

Stavo cercando un modo veloce per fare l'argomento, quindi ho fatto alcuni esperimenti con modi suggeriti. E sono rimasto sorpreso dai risultati, quindi voglio condividerlo con te.

Gli esperimenti sono stati fatti usando pythonbenchmark strumento e con

a = range(1,50000) # Source list 
b = range(1,15000) # Items to remove 

Risultati:

def comprehension(a, b): 
    return [x for x in a if x not in b] 

5 tentativi, tempo medio di 12.8 sec

def filter_function(a, b): 
    return filter(lambda x: x not in b, a) 

5 tentativi, tempo medio di 12.6 sec

def modification(a,b): 
    for x in b: 
     try: 
      a.remove(x) 
     except ValueError: 
      pass 
    return a 

5 tentativi, tempo medio 0,27 sec

def set_approach(a,b): 
    return list(set(a)-set(b)) 

5 tentativi, tempo medio 0,0057 sec

Inoltre ho fatto un'altra misura con dimensioni ingressi più grandi per le ultime due funzioni

a = range(1,500000) 
b = range(1,100000) 

E i risultati:

Per modifica (rimuovere metodo) - tempo medio è di 252 secondi per l'approccio set - il tempo medio è di 0,75 secondo

Così si può vedere che l'approccio con i set è significativamente più velocemente di altri. Sì, non conserva oggetti simili, ma se non ne hai bisogno, è per te. E non c'è quasi nessuna differenza tra la comprensione degli elenchi e l'uso della funzione filtro. L'uso di "Rimuovi" è ~ 50 volte più veloce, ma modifica l'elenco delle fonti. E la scelta migliore è usare i set: è più di 1000 volte più veloce della comprensione delle liste!

+0

molto interessante. Non avrei usato set, intuitivamente la conversione dovrebbe aggiungere un overhead. a quanto pare la mia intuizione era sbagliata. grazie per l'intuizione – lhk

Problemi correlati