remove Nenhum valor de uma lista sem remover o valor 0

244

Esta foi a minha fonte que eu comecei.

Minha lista

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

Quando eu executo isso:

L = filter(None, L)

Eu recebo esses resultados

[23, 234, 89, 35, 9]

Mas não é disso que preciso, o que realmente preciso é:

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

Porque eu estou calculando o percentil dos dados e o 0 faz muita diferença.

Como remover o valor Nenhum de uma lista sem remover o valor 0?

mongotop
fonte

Respostas:

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]

Apenas por diversão, veja como você pode se adaptar filterpara fazer isso sem usar a lambda, (eu não recomendaria esse código - é apenas para fins 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
fonte
23
A filterversão menos elegante : filter(lambda x: x is not None, L)- Você pode se livrar do lambdauso partiale operator.is_noteu acho, mas provavelmente não vale a pena, pois a lista-comp é muito mais limpa.
mgilson
3
@mgilson Oh uau, eu nem sabia que is_notexistia! Eu pensei que era apenas is_, eu vou acrescentar que, em apenas por diversão
jamylak
@jamylak - Sim. Na verdade, me incomoda o que is_notexiste e o not_inque não existe. Na verdade, acho que isso not_indeve ser transformado em um método mágico __not_contains__... veja uma pergunta que fiz há um tempo e um comentário que fiz a um respondente ... e ainda não sinto que isso foi resolvido.
mgilson
@ mgilson Eu acho que sob essa mesma suposição, eu apenas assumi que não existia. Eu acho que você pode apenas usar filterfalseou algo dependendo do caso de uso
jamylak
@jamylak - Sim. Meu principal problema é que x > ynão implica not x <= yem python, porque você pode fazer qualquer coisa em __lt__e __le__, então por que x not in yimplicam not x in y(especialmente desde que not intem seu próprio bytecode?)
mgilson
136

FWIW, Python 3 facilita esse problema:

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

No Python 2, você usaria uma compreensão de lista:

>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]
Raymond Hettinger
fonte
+1 Você recomenda o uso desse __ne__tipo em oposição a partiale ne?
jamylak
1
@jamylak Sim, é mais rápido, um pouco mais fácil de escrever e um pouco mais claro.
Raymond Hettinger
Considere usar o operatormódulo.
rightfold
12
O que é __ne__?
DrMcCleod
11
@DrMcCleod A expressão x != ychama internamente x.__ne__(y)onde ne significa "diferente de". Portanto, None.__ne__é um método vinculado que retorna True quando chamado com qualquer valor diferente de Nenhum . Por exemplo, bm = None.__ne__chamado with bm(10)retorna NotImplemented, que como valor verdadeiro, e bm(None)retorna False .
Raymond Hettinger
17

Usando a compreensão da lista, isso pode ser feito da seguinte maneira:

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

O valor de l é:

[0, 23, 234, 89, 0, 35, 9]
DotPi
fonte
Essa solução já foi encontrada na resposta superior ou estou faltando alguma coisa?
Qaswed
16

Para Python 2.7 (consulte a resposta de Raymond, para equivalente em Python 3):

Querendo saber se algo "não é Nenhum" é tão comum no python (e em outras linguagens OO), que no meu Common.py (que importo para cada módulo com "do Common import *"), incluo estas linhas:

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

Para remover os elementos Nenhum de uma lista, basta:

filter(exists, L)

Acho isso mais fácil de ler do que a compreensão da lista correspondente (que Raymond mostra, como sua versão do Python 2).

Fabricante de ferramentas
fonte
Eu preferiria a solução Raymonds para o Python 3 e, em seguida, a compreensão da lista para o Python 2. Mas se eu tivesse que seguir esse caminho, preferiria partial(is_not, None)que essa solução. Eu acredito que isso será mais lento (embora isso não seja muito importante). Mas com um par de importações de módulos python, há necessidade de um personalizado definido função neste caso
jamylak
12

A resposta do @jamylak é bastante agradável, no entanto, se você não deseja importar alguns módulos apenas para executar esta tarefa simples, escreva seu próprio lambdalocal:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(lambda v: v is not None, L)
[0, 23, 234, 89, 0, 35, 9]
AT
fonte
Você obviamente não leu a minha solução corretamente que é [x for x in L if x is not None]o outro código era apenas uma adição i explicitamente declarado não recomendar
jamylak
1
@jamylak - eu li, mas você não incluiu esta solução. - Também não sei por que você está editando as respostas das pessoas de 4 a 5 anos atrás.
AT
5

Iteração x Espaço , o uso pode ser um problema. Em diferentes situações, a criação de perfil pode mostrar ser "mais rápida" e / ou "menos memória" 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, ...]

A primeira abordagem (como também sugerida por @jamylak , @Raymond Hettinger e @Dipto ) cria uma lista duplicada na memória, o que pode custar caro para uma lista grande com poucosNone entradas.

A segunda abordagem percorre a lista uma vez e novamente a cada vez até que a Noneseja atingida. Isso pode consumir menos memória e a lista fica menor à medida que avança. A diminuição no tamanho da lista pode acelerar a Noneentrada de muitas entradas na frente, mas o pior caso seria se muitasNone entradas estivessem na parte de trás.

Paralelização e técnicas no local são outras abordagens, mas cada uma tem suas próprias complicações em Python. Conhecer os casos de uso de dados e tempo de execução, bem como criar um perfil do programa, é o ponto de partida para operações intensivas ou grandes dados.

A escolha de qualquer abordagem provavelmente não será importante em situações comuns. Torna-se mais uma preferência de notação. De fato, nessas circunstâncias incomuns, numpyou cythonpodem ser alternativas que valem a pena, em vez de tentar microgerenciar otimizações de Python.

Kevin
fonte
Não é um fã disso, a vantagem que você alega com esta solução é que a lista pode ser tão grande que a criação de uma lista duplicada na memória pode ser cara. Bem, sua solução será ainda mais cara, porque você está pesquisando a lista inteira L.count(None)e ligando .remove(None)várias vezes, o que torna O(N^2)a situação que você está tentando resolver não deve ser tratada dessa maneira, os dados devem ser reestruturados em um banco de dados ou arquivo em vez disso, se tiver muita memória.
jamylak
@jamylak É verdade, mas nem todas as situações ou dados do mundo real permitem essa flexibilidade. Por exemplo, bombeando dados geoespaciais "legados" por meio de uma análise pontual em um sistema sem muita memória. Também há tempo de programação versus tempo de execução a considerar. As pessoas geralmente recorrem ao Python por causa da economia no tempo de desenvolvimento. Com esta resposta, estou chamando a atenção para o fato de que vale a pena considerar a memória, mas afirmo no final que é principalmente a preferência individual na notação. Também aponto que conhecer os dados é importante. O(n^2)é somente quando a lista inteira é None.
Kevin
Você ficaria interessado se você tivesse um exemplo prático em que essa resposta seja a melhor solução, eu acho que haveria uma abordagem melhor em todos os casos. Por exemplo numpyseria capaz de lidar com este tipo de operação de uma forma mais optimizada
jamylak
@jamylak Para ser justo, tenho usado numpynos últimos anos, mas é uma habilidade separada. Se Lfor instanciado como um em numpy.arrayvez de um Python list, L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) provavelmente será melhor que qualquer um dos dois, mas eu não conheço os detalhes de implementação para processamento vs memória abaixo. Pelo menos, cria uma matriz de booleanos de comprimento duplicado para a máscara. A sintaxe de uma comparação dentro de um operador de acesso (índice), dessa forma, é nova para mim. Essa discussão também chamou minha atenção dtype=object.
21718 Kevin
Essa discussão está ficando muito abstrata agora, acho que você não poderia me dar um exemplo da vida real nos seus anos de experiência em que essa resposta é a abordagem correta sobre a reestruturação dos dados, como mencionei 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
fonte
6
Por favor, forneça algumas informações detalhadas ao OP, e não apenas um código.
Laurent LAPORTE
1
Eu fiz. O que você acha?
23816 med_abidi
Bem, isso não responde à pergunta do OP. Considere esta resposta: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE 23/11
Sim você está certo. Houve um problema com o filtro parcial.
23816 med_abidi
2

Se é tudo uma lista de listas, você pode modificar a resposta de sir @ Raymond

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

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

<< list_indice [0] para a variável na Lista se a variável não for Nenhuma >>

Skrmnghrd
fonte
1

Digamos que a lista seja como abaixo

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

Isso retornará apenas os itens cujos bool(item) is True

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

Isso é equivalente a

print [item for item in iterator if item]

Para filtrar apenas Nenhum:

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 obter todos os itens avaliados como False

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