rimuovere il valore Nessuno da un elenco senza rimuovere il valore 0


245

Questa è stata la mia fonte con cui ho iniziato.

La mia lista

L = [0, 23, 234, 89, None, 0, 35, 9]

Quando eseguo questo:

L = filter(None, L)

Ottengo questi risultati

[23, 234, 89, 35, 9]

Ma questo non è ciò di cui ho bisogno, ciò di cui ho veramente bisogno è:

[0, 23, 234, 89, 0, 35, 9]

Perché sto calcolando il percentile dei dati e lo 0 fa molta differenza.

Come rimuovere il valore Nessuno da un elenco senza rimuovere il valore 0?

Risposte:


355
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]

Solo per divertimento, ecco come puoi adattarti filterper farlo senza usare un lambda(non consiglierei questo codice - è solo per scopi scientifici)

>>> from operator import is_not
>>> from functools import partial
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(partial(is_not, None), L)
[0, 23, 234, 89, 0, 35, 9]

23
La filterversione meno elegante : filter(lambda x: x is not None, L)- Potresti sbarazzarti lambdadell'uso partiale operator.is_notpenso, ma probabilmente non ne vale la pena poiché l'elenco-comp è molto più pulito.
mgilson

3
@mgilson Oh wow non sapevo nemmeno che is_notesistesse! Pensavo fosse solo is_, lo aggiungerò solo per divertimento
jamylak,

@jamylak - Sì. In realtà mi dà fastidio che is_notesiste e not_innon esiste. In realtà penso che not_indovrebbe essere trasformato in un metodo magico __not_contains__... vedi una domanda che ho posto qualche tempo fa e un commento che ho fatto a un risponditore ... e ancora non mi sento come se fosse risolto.
mgilson

@mgilson Penso che con lo stesso presupposto ho appena pensato che non esistesse. Immagino che tu possa semplicemente usare filterfalseo qualcosa del genere a seconda del caso d'uso
jamylak

@jamylak - Sì. Il mio problema principale è che x > ynon implica not x <= yin Python perché puoi fare qualsiasi cosa in __lt__e __le__, quindi perché dovrebbe x not in yimplicare not x in y(soprattutto perché not inha il suo bytecode?)
mgilson

136

FWIW, Python 3 semplifica questo problema:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> list(filter(None.__ne__, L))
[0, 23, 234, 89, 0, 35, 9]

In Python 2, invece, dovresti utilizzare una comprensione dell'elenco:

>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]

+1 Raccomandi l'uso di __ne__like that al contrario di partiale ne?
jamylak,

1
@jamylak Sì, è più veloce, un po 'più facile da scrivere e un po' più chiaro.
Raymond Hettinger,

Prendi in considerazione l'utilizzo del operatormodulo.
destra del

12
Che cosa è __ne__?
DrMcCleod,

11
@DrMcCleod L'espressione x != ychiama internamente x.__ne__(y)dove ne sta per "non uguale". Quindi, None.__ne__è un metodo associato che restituisce True quando viene chiamato con qualsiasi valore diverso da Nessuno . Ad esempio, bm = None.__ne__chiamato con bm(10)restituisce NotImplemented quale come valore vero e bm(None)restituisce False .
Raymond Hettinger,

17

Usando la comprensione dell'elenco questo può essere fatto come segue:

l = [i for i in my_list if i is not None]

Il valore di l è:

[0, 23, 234, 89, 0, 35, 9]

1
Questa soluzione si trova già nella risposta migliore o mi manca qualcosa?
Riassunto

16

Per Python 2.7 (vedi la risposta di Raymond, per l'equivalente in Python 3):

Volendo sapere se qualcosa "non è nessuno" è così comune in Python (e in altri linguaggi OO), che nel mio Common.py (che io importa in ogni modulo con "da Common import *"), includo queste righe:

def exists(it):
    return (it is not None)

Quindi per rimuovere Nessuno elementi da un elenco, fai semplicemente:

filter(exists, L)

Lo trovo più facile da leggere, rispetto alla corrispondente comprensione dell'elenco (che Raymond mostra, come la sua versione di Python 2).


Preferirei la soluzione Raymonds per Python 3, e quindi la comprensione dell'elenco per Python 2. Ma se dovessi seguire questa strada, preferirei partial(is_not, None)questa soluzione. Credo che questo sarà più lento (anche se non troppo importante). Ma con un paio di importazioni di moduli Python, in questo caso non è necessaria una funzione personalizzata
jamylak,

12

La risposta di @jamylak è abbastanza buona, tuttavia se non vuoi importare un paio di moduli solo per fare questo semplice compito, scrivi sul lambdaposto:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(lambda v: v is not None, L)
[0, 23, 234, 89, 0, 35, 9]

Ovviamente non hai letto correttamente la mia soluzione, che è [x for x in L if x is not None]l'altro codice era solo un'aggiunta che ho dichiarato esplicitamente che non avrei raccomandato
jamylak,

1
@jamylak - L'ho letto, ma non avevi incluso questa soluzione. - Inoltre, non so perché stai modificando le risposte delle persone da 4-5 anni fa.
AL

5

Iterazione vs spazio , l'utilizzo potrebbe essere un problema. In diverse situazioni la profilazione può mostrare di essere "più veloce" e / o "meno memoria".

# first
>>> L = [0, 23, 234, 89, None, 0, 35, 9, ...]
>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9, ...]

# second
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> for i in range(L.count(None)): L.remove(None)
[0, 23, 234, 89, 0, 35, 9, ...]

Il primo approccio (come suggerito anche da @jamylak , @Raymond Hettinger e @Dipto ) crea un elenco duplicato in memoria, che potrebbe essere costoso per un elenco di grandi dimensioni con poche Nonevoci.

Il secondo approccio passa attraverso l'elenco una volta e poi di nuovo ogni volta fino a quando Noneviene raggiunto un. Ciò potrebbe richiedere meno memoria e l'elenco diventerà più piccolo man mano che procede. La riduzione delle dimensioni dell'elenco potrebbe accelerare per molte Nonevoci nella parte anteriore, ma il caso peggiore sarebbe se molte Nonevoci fossero nella parte posteriore.

Parallelizzazione e tecniche sul posto sono altri approcci, ma ognuno ha le proprie complicazioni in Python. Conoscere i dati e i casi d'uso del runtime, nonché la profilazione del programma sono da dove iniziare per operazioni intensive o dati di grandi dimensioni.

Scegliere uno dei due approcci probabilmente non avrà importanza in situazioni comuni. Diventa più una preferenza di notazione. In effetti, in quelle circostanze insolite, numpyo cythonpotrebbero essere alternative utili invece di tentare di micromanage le ottimizzazioni di Python.


Non è affatto un fan di questo, l'intero vantaggio che rivendichi con questa soluzione è che l'elenco potrebbe essere così grande che la creazione di un elenco duplicato in memoria potrebbe essere costosa. Bene, allora la tua soluzione sarà ancora più costosa perché stai scannerizzando l'intero elenco L.count(None)e quindi stai chiamando .remove(None)più volte, il che rende questo O(N^2)La situazione che stai cercando di risolvere non dovrebbe essere gestita in questo modo, i dati dovrebbero essere ristrutturati in un database o file invece se è quella memoria intensiva.
jamylak,

@jamylak Vero, ma non tutte le situazioni o i dati del mondo reale consentono tale flessibilità. Ad esempio, il pompaggio di dati geospaziali "legacy" attraverso un'analisi una tantum su un sistema senza molta memoria. Quindi c'è anche tempo di programmazione vs runtime da considerare. Le persone spesso si rivolgono a Python a causa dei risparmi nei tempi di sviluppo. Con questa risposta, sto portando l'attenzione sul fatto che la memoria potrebbe valere la pena di essere presa in considerazione, ma dichiaro alla fine che si tratta principalmente di preferenze individuali nella notazione. Sottolineo inoltre che conoscere i dati è importante. O(n^2)è solo quando l'intero elenco è None.
Kevin,

Sarei interessato se avessi un esempio pratico in cui questa risposta è la soluzione migliore, tendo a pensare che ci sarebbe un approccio migliore in tutti i casi. Ad esempio numpysarebbe in grado di gestire questo tipo di operazione in modo più ottimizzato
jamylak,

@jamylak Per essere onesti, ho usato numpynegli ultimi anni, ma è un'abilità separata. Se Lviene istanziato come un numpy.arrayPython invece list, L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) è probabilmente migliore di entrambi, ma non conosco i dettagli di implementazione per l'elaborazione rispetto alla memoria sottostante. Crea almeno un array di lunghezza booleana duplicato per la maschera. La sintassi di un confronto all'interno di un operatore di accesso (indice), in questo modo, è nuova per me. Questa discussione ha anche portato alla mia attenzione dtype=object.
Kevin,

Questa discussione sta diventando troppo astratta ora, non credo che saresti in grado di darmi un esempio di vita reale nei tuoi anni di esperienza in cui questa risposta è l'approccio corretto sulla ristrutturazione dei dati, come ho detto prima.
jamylak,

2
from operator import is_not
from functools import partial   

filter_null = partial(filter, partial(is_not, None))

# A test case
L = [1, None, 2, None, 3]
L = list(filter_null(L))

6
Fornire alcune informazioni dettagliate all'OP e non solo un codice.
Laurent LAPORTE,

1
L'ho fatto. Cosa ne pensi?
med_abidi,

Bene, questo non risponde alla domanda OP. Considerate questa risposta invece: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE

Si hai ragione. Si è verificato un problema con il filtro parziale.
med_abidi,

2

Se è tutto un elenco di elenchi, è possibile modificare la risposta di sir @ Raymond

L = [ [None], [123], [None], [151] ] no_none_val = list(filter(None.__ne__, [x[0] for x in L] ) ) per Python 2 tuttavia

no_none_val = [x[0] for x in L if x[0] is not None] """ Both returns [123, 151]"""

<< list_indice [0] per la variabile in List se la variabile non è None >>


1

Di 'che la lista è come sotto

iterator = [None, 1, 2, 0, '', None, False, {}, (), []]

Questo restituirà solo quegli articoli di cui bool(item) is True

print filter(lambda item: item, iterator)
# [1, 2]

Questo equivale a

print [item for item in iterator if item]

Per filtrare solo Nessuno:

print filter(lambda item: item is not None, iterator)
# [1, 2, 0, '', False, {}, (), []]

Equivalente a:

print [item for item in iterator if item is not None]

Per ottenere tutti gli elementi che valutano Falso

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.