supprimer la valeur None d'une liste sans supprimer la valeur 0


245

C'était ma source avec laquelle j'ai commencé.

Ma liste

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

Quand je lance ceci:

L = filter(None, L)

J'obtiens ces résultats

[23, 234, 89, 35, 9]

Mais ce n'est pas ce dont j'ai besoin, ce dont j'ai vraiment besoin c'est:

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

Parce que je calcule le centile des données et le 0 fait beaucoup de différence.

Comment supprimer la valeur None d'une liste sans supprimer la valeur 0?

Réponses:


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]

Juste pour le plaisir, voici comment vous pouvez vous y adapter filtersans utiliser de lambda, (je ne recommanderais pas ce code - c'est juste à des fins scientifiques)

>>> 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 filterversion moins élégante : filter(lambda x: x is not None, L)- Vous pourriez vous débarrasser de l' lambdautilisation partialet operator.is_notje pense, mais ça ne vaut probablement pas la peine car la liste-comp est tellement plus propre.
mgilson

3
@mgilson Oh wow, je ne savais même pas qu'il is_notexistait! Je pensais que c'était seulement is_, je vais ajouter ça juste pour le plaisir
jamylak

@jamylak - Ouais. Cela me dérange en fait d' is_notexister et d' not_inexister. En fait, je pense que cela not_indevrait être transformé en une méthode magique __not_contains__... voir une question que j'ai posée il y a un certain temps et un commentaire que j'ai fait à un répondeur ... et je n'ai toujours pas l'impression que c'est résolu.
mgilson

@mgilson Je pense que sous cette même hypothèse, je pensais juste qu'elle n'existait pas. Je suppose que vous pouvez simplement utiliser filterfalseou quelque chose en fonction du cas d'utilisation
jamylak

@jamylak - Ouais. Mon principal problème est que x > ycela n'implique pas not x <= yen python parce que vous pouvez faire quoi que ce soit dedans __lt__et __le__, alors pourquoi devrait x not in yimpliquer not x in y(d'autant plus not inqu'il a son propre bytecode?)
mgilson

136

FWIW, Python 3 facilite ce problème:

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

En Python 2, vous utiliseriez plutôt une compréhension de liste:

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

+1 Recommandez-vous l'utilisation de __ne__comme ça plutôt que partialet ne?
jamylak

1
@jamylak Oui, c'est plus rapide, un peu plus facile à écrire et un peu plus clair.
Raymond Hettinger

Pensez à utiliser le operatormodule.
droite le

12
Qu'est-ce que c'est __ne__?
DrMcCleod

11
@DrMcCleod L'expression x != yappelle en interne x.__ne__(y)ne signifie "non égal". Il None.__ne__s'agit donc d'une méthode liée qui renvoie True lorsqu'elle est appelée avec une valeur autre que None . Par exemple, bm = None.__ne__appelé avec bm(10)renvoie NotImplemented qui a la valeur true et bm(None)renvoie False .
Raymond Hettinger

17

En utilisant la compréhension de la liste, cela peut être fait comme suit:

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

La valeur de l est:

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

1
Cette solution se trouve déjà dans la première réponse, ou ai-je oublié quelque chose?
Qaswed

16

Pour Python 2.7 (Voir la réponse de Raymond, pour l'équivalent Python 3):

Vouloir savoir si quelque chose "n'est pas None" est si courant en python (et dans d'autres langages OO), que dans mon Common.py (que j'importe dans chaque module avec "from Common import *"), j'inclus ces lignes:

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

Ensuite, pour supprimer les éléments None d'une liste, faites simplement:

filter(exists, L)

Je trouve cela plus facile à lire que la compréhension de la liste correspondante (que Raymond montre, comme sa version Python 2).


Je préférerais la solution Raymonds pour Python 3, puis la compréhension de la liste pour Python 2. Mais si je devais suivre cette voie, je préférerais partial(is_not, None)cette solution. Je crois que ce sera plus lent (bien que ce ne soit pas trop important). Mais avec quelques importations de modules python, pas besoin de fonction définie dans ce cas
jamylak

12

La réponse de @jamylak est assez agréable, cependant si vous ne voulez pas importer quelques modules juste pour faire cette tâche simple, écrivez votre propre lambdasur place:

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

Vous n'avez évidemment pas lu correctement ma solution qui est [x for x in L if x is not None] l'autre code n'était qu'un ajout que j'ai explicitement déclaré que je ne recommanderais pas
jamylak

1
@jamylak - Je l'ai lu, mais vous n'aviez pas inclus cette solution. - Vous ne savez pas non plus pourquoi vous modifiez les réponses des gens d'il y a 4 à 5 ans.
AU

5

Itération vs espace , l'utilisation pourrait être un problème. Dans différentes situations, le profilage peut s'avérer être "plus rapide" et / ou "moins gourmand en mémoire".

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

La première approche (comme le suggèrent également @jamylak , @Raymond Hettinger et @Dipto ) crée une liste en double en mémoire, ce qui pourrait être coûteux pour une grande liste avec peuNone entrées.

La deuxième approche parcourt la liste une fois, puis à chaque fois jusqu'à ce que a Nonesoit atteint. Cela pourrait être moins gourmand en mémoire et la liste se réduira au fur et à mesure. La diminution de la taille de la liste pourrait avoir une accélération pour de nombreuses Noneentrées à l'avant, mais le pire des cas serait si beaucoup deNone entrées étaient à l'arrière.

La parallélisation et les techniques sur place sont d'autres approches, mais chacune a ses propres complications en Python. Connaître les données et les cas d'utilisation d'exécution, ainsi que le profilage du programme sont où commencer pour des opérations intensives ou des données volumineuses.

Le choix de l'une ou l'autre approche n'aura probablement pas d'importance dans les situations courantes. Cela devient plus une préférence de notation. En fait, dans ces circonstances inhabituelles, numpyoucython peuvent être des alternatives valables au lieu de tenter de microgérer les optimisations Python.


Pas du tout fan de tout cela, tout l'avantage que vous revendiquez avec cette solution est que la liste peut être si énorme que la création d'une liste en double en mémoire peut être coûteuse. Eh bien, votre solution sera encore plus coûteuse car vous balayez toute la liste L.count(None)et vous appelez .remove(None)plusieurs fois, ce qui rend O(N^2)la situation que vous essayez de résoudre ne doit pas être traitée de cette manière, les données doivent être restructurées dans une base de données ou un fichier à la place si la mémoire est importante.
jamylak

@jamylak Certes, mais toutes les situations ou données du monde réel ne permettent pas cette flexibilité. Par exemple, pomper des données géospatiales «héritées» grâce à une analyse ponctuelle sur un système sans beaucoup de mémoire. Ensuite, il y a aussi le temps de programmation vs le temps d'exécution à considérer. Les gens se tournent souvent vers Python en raison des économies de temps de développement. Avec cette réponse, j'attire l'attention sur le fait que la mémoire peut être utile à considérer, mais je déclare à la fin qu'il s'agit principalement d'une préférence individuelle en notation. Je souligne également que la connaissance des données est importante. O(n^2)est uniquement lorsque la liste entière est None.
Kevin

Serait intéressé si vous aviez un exemple pratique où cette réponse est la meilleure solution, j'ai tendance à penser qu'il y aurait une meilleure approche dans tous les cas. Par exemple, numpyserait capable de gérer ce type d'opération de manière plus optimisée
jamylak

@jamylak Pour être honnête, j'utilise numpyces dernières années, mais c'est une compétence distincte. Si Lest instancié en tant que numpy.arrayau lieu d'un Python list, alors L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) est probablement meilleur que l'un ou l'autre, mais je ne connais pas les détails d'implémentation pour le traitement par rapport à la mémoire en dessous. Il crée au moins un tableau de longueur en double de booléens pour le masque. La syntaxe d'une comparaison à l'intérieur d'un opérateur d'accès (index), de cette façon, est nouvelle pour moi. Cette discussion a également attiré mon attention dtype=object.
Kevin

Cette discussion devient trop abstraite maintenant, je ne pense pas que vous seriez en mesure de me donner un exemple réel dans vos années d'expérience où cette réponse est la bonne approche pour restructurer les données comme je l'ai mentionné précédemment.
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
Veuillez donner des informations détaillées à l'OP, et pas seulement un code.
Laurent LAPORTE

1
J'ai fait. Ce que tu penses?
med_abidi

Eh bien, cela ne répond pas à la question OP. Considérez plutôt cette réponse: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE

Oui, tu as raison. Il y a eu un problème avec le filtre partiel.
med_abidi

2

S'il ne s'agit que d'une liste de listes, vous pouvez modifier la réponse de monsieur @ Raymond

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

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

<< list_indice [0] pour la variable dans la liste si la variable n'est pas Aucune >>


1

Dites que la liste est comme ci-dessous

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

Cela ne retournera que les articles dont bool(item) is True

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

Cela équivaut à

print [item for item in iterator if item]

Pour filtrer simplement Aucun:

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

Équivalent à:

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

Pour obtenir tous les éléments évalués comme faux

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.