eliminar el valor None de una lista sin eliminar el valor 0

244

Esta fue mi fuente con la que comencé.

Mi lista

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

Cuando ejecuto esto:

L = filter(None, L)

Obtengo estos resultados

[23, 234, 89, 35, 9]

Pero esto no es lo que necesito, lo que realmente necesito es:

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

Porque estoy calculando el percentil de los datos y el 0 hace una gran diferencia.

¿Cómo eliminar el valor None de una lista sin eliminar el valor 0?

mongotop
fuente

Respuestas:

354
>>> 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 por diversión, así es como puede adaptarse filterpara hacer esto sin usar un lambda, (no recomendaría este código, es solo para fines científicos)

>>> 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]
jamylak
fuente
23
La filterversión menos elegante : filter(lambda x: x is not None, L)- Podrías deshacerte del lambdauso partialy operator.is_notcreo, pero probablemente no valga la pena ya que la lista de compilación es mucho más limpia.
mgilson
3
@mgilson ¡Vaya, ni siquiera sabía que is_notexistía! Pensé que era solo is_, lo
agregaré
@jamylak - Sí. Realmente me molesta que is_notexista y not_inque no exista. De hecho, creo que not_indebería convertirse en un método mágico __not_contains__... veo una pregunta que hice hace un tiempo y un comentario que hice a un respondedor ... y todavía no siento que se haya resuelto.
mgilson
@mgilson Creo que bajo esa misma suposición, asumí que no existía. Supongo que puedes usar filterfalseo algo dependiendo del caso de uso
jamylak
@jamylak - Sí. Mi principal problema es que x > yno implica not x <= yen Python porque puede hacer cualquier cosa __lt__y __le__, entonces, ¿por qué debería x not in yimplicar not x in y(especialmente porque not intiene su propio
código de bytes
136

FWIW, Python 3 facilita este problema:

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

En Python 2, usaría una lista de comprensión en su lugar:

>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]
Raymond Hettinger
fuente
+1 ¿Recomiendas el uso de __ne__ese tipo en lugar de partialy ne?
jamylak
1
@jamylak Sí, es más rápido, un poco más fácil de escribir y un poco más claro.
Raymond Hettinger
Considere usar el operatormódulo.
derecha
12
¿Qué es __ne__?
DrMcCleod
11
@DrMcCleod La expresión x != yllama internamente x.__ne__(y)donde ne significa "no igual". Entonces, None.__ne__es un método enlazado que devuelve True cuando se llama con cualquier valor que no sea None . Por ejemplo, bm = None.__ne__llamado con bm(10)retornos NotImplemented que como valor verdadero, y bm(None)devuelve False .
Raymond Hettinger
17

Usando la comprensión de la lista esto se puede hacer de la siguiente manera:

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

El valor de l es:

[0, 23, 234, 89, 0, 35, 9]
DotPi
fuente
Esta solución ya se encuentra en la respuesta principal, ¿o me falta algo?
Qaswed
16

Para Python 2.7 (Ver la respuesta de Raymond, para el equivalente de Python 3):

Queriendo saber si algo "no es Ninguno" es tan común en python (y otros lenguajes OO), que en mi Common.py (que importo a cada módulo con "Importación común *"), incluyo estas líneas:

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

Luego, para eliminar elementos None de una lista, simplemente haga:

filter(exists, L)

Me resulta más fácil de leer que la comprensión de la lista correspondiente (que Raymond muestra, como su versión de Python 2).

ToolmakerSteve
fuente
Preferiría la solución Raymonds para Python 3, y luego la comprensión de la lista para Python 2. Pero si tuviera que seguir esta ruta, preferiría partial(is_not, None)esta solución. Creo que esto será más lento (aunque eso no es demasiado importante). Pero con un par de importaciones de módulos de Python, no es necesaria una función personalizada definida en este caso
jamylak
12

La respuesta de @jamylak es bastante agradable, sin embargo, si no desea importar un par de módulos solo para hacer esta tarea simple, escriba su propio lambdalugar:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(lambda v: v is not None, L)
[0, 23, 234, 89, 0, 35, 9]
A
fuente
Obviamente, no leyó mi solución correctamente, que es [x for x in L if x is not None]el otro código, fue solo una adición que
dije
1
@jamylak: lo leí, pero no incluiste esta solución. - Tampoco estoy seguro de por qué está editando las respuestas de las personas de hace 4 a 5 años.
AL
5

Iteración vs espacio , el uso podría ser un problema. En diferentes situaciones, la elaboración de perfiles puede mostrar que es "más rápida" y / o "menos memoria" intensiva.

# 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, ...]

El primer enfoque (como también lo sugirieron @jamylak , @Raymond Hettinger y @Dipto ) crea una lista duplicada en la memoria, lo que podría ser costoso para una lista grande con pocas Noneentradas.

El segundo enfoque pasa por la lista una vez, y luego otra vez cada vez hasta que Nonese alcanza a. Esto podría consumir menos memoria y la lista se hará más pequeña a medida que avanza. La disminución en el tamaño de la lista podría acelerar una gran cantidad de Noneentradas en el frente, pero el peor de los casos sería si muchas Noneentradas estuvieran en la parte posterior.

La paralelización y las técnicas in situ son otros enfoques, pero cada uno tiene sus propias complicaciones en Python. Conocer los datos y los casos de uso de tiempo de ejecución, así como perfilar el programa, es el punto de partida para operaciones intensivas o datos de gran tamaño.

Elegir cualquiera de los enfoques probablemente no importará en situaciones comunes. Se convierte más en una preferencia de notación. De hecho, en esas circunstancias poco comunes, numpyo cythonpuede ser una alternativa que valga la pena, en lugar de intentar gestionar las optimizaciones de Python.

Kevin
fuente
No soy fanático de esto en absoluto, toda la ventaja que reclamas con esta solución es que la lista podría ser tan grande que construir listas duplicadas en la memoria podría ser costoso. Bueno, entonces su solución será aún más costosa porque está escaneando la lista completa L.count(None)y luego está llamando .remove(None)varias veces, lo que hace que la O(N^2)situación que está tratando de resolver no se aborde de esta manera, los datos deben reestructurarse en una base de datos o archivo en su lugar si es tan intensivo en memoria.
jamylak
@jamylak Es cierto, pero no todas las situaciones o datos del mundo real permiten esa flexibilidad. Por ejemplo, bombear datos geoespaciales "heredados" a través de un análisis único en un sistema sin mucha memoria. Luego también hay que considerar el tiempo de programación vs tiempo de ejecución. Las personas a menudo recurren a Python debido a los ahorros en tiempo de desarrollo. Con esta respuesta, estoy llamando la atención sobre el hecho de que vale la pena considerar la memoria, pero al final afirmo que es principalmente una preferencia individual en notación. También señalo que conocer los datos es importante. O(n^2)es solo cuando toda la lista es None.
Kevin
Estaría interesado si tuviera un ejemplo práctico donde esta respuesta es la mejor solución, tiendo a pensar que habría un mejor enfoque en todos los casos. Por ejemplo numpy, sería capaz de manejar este tipo de operación de una manera más optimizada
jamylak,
@jamylak Para ser justos, he estado usando numpyen los últimos años, pero es una habilidad separada. Si Lse instancia como un numpy.arrayPython en lugar de un Python list, entonces L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) es probablemente mejor que cualquiera de los dos, pero no conozco los detalles de implementación para el procesamiento frente a la memoria debajo. Al menos crea una matriz de booleanos de longitud duplicada para la máscara. La sintaxis de una comparación dentro de un operador de acceso (índice), de esa manera, es nueva para mí. Esta discusión también me ha llamado la atención dtype=object.
Kevin
Esta discusión se está volviendo demasiado abstracta ahora, no creo que pueda darme un ejemplo de la vida real en sus años de experiencia donde esta respuesta es el enfoque correcto sobre la reestructuración de los datos como mencioné antes.
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))
med_abidi
fuente
66
Por favor, brinde información detallada al OP, y no solo un código.
Laurent LAPORTE
1
Yo hice. ¿Qué piensas?
med_abidi
Bueno, esto no responde la pregunta de OP. Considere esta respuesta en su lugar: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE
Sí, tiene usted razón. Hubo un problema con el filtro parcial.
med_abidi
2

Si se trata de una lista de listas, puede modificar la respuesta de sir @ Raymond

L = [ [None], [123], [None], [151] ] no_none_val = list(filter(None.__ne__, [x[0] for x in L] ) ) para python 2 sin embargo

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

<< list_indice [0] para la variable en Lista si la variable no es Ninguna >>

Skrmnghrd
fuente
1

Digamos que la lista es como abajo

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

Esto devolverá solo aquellos artículos cuyo bool(item) is True

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

Esto es equivalente a

print [item for item in iterator if item]

Para filtrar Ninguno:

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]

Para obtener todos los elementos que evalúan como Falso

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
theBuzzyCoder
fuente