Entfernen Sie den Wert None aus einer Liste, ohne den Wert 0 zu entfernen

244

Dies war meine Quelle, mit der ich angefangen habe.

Meine Liste

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

Wenn ich das mache:

L = filter(None, L)

Ich bekomme diese Ergebnisse

[23, 234, 89, 35, 9]

Aber das ist nicht was ich brauche, was ich wirklich brauche ist:

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

Weil ich das Perzentil der Daten berechne und die 0 einen großen Unterschied macht.

Wie entferne ich den Wert None aus einer Liste, ohne den Wert 0 zu entfernen?

Mongotop
quelle

Antworten:

353
>>> 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]

Nur zum Spaß, hier ist, wie Sie sich anpassen können, filterohne ein zu verwenden lambda(ich würde diesen Code nicht empfehlen - er dient nur wissenschaftlichen Zwecken)

>>> 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
quelle
23
Die weniger elegante filterVersion: filter(lambda x: x is not None, L)- Sie könnten die lambdaVerwendung loswerden partialund operator.is_notich denke, aber es lohnt sich wahrscheinlich nicht, da die Listen-Komposition so viel sauberer ist.
mgilson
3
@mgilson Oh wow ich wusste nicht mal dass es is_notexistiert! Ich dachte es wäre nur is_, ich werde das nur zum Spaß hinzufügen
Jamylak
@ Jamylak - Ja. Es stört mich tatsächlich, dass es is_notexistiert und not_innicht existiert. Ich denke eigentlich, dass not_indies zu einer magischen Methode werden sollte __not_contains__... siehe eine Frage, die ich vor einiger Zeit gestellt habe, und einen Kommentar, den ich einem Antwortenden gegeben habe ... und ich habe immer noch nicht das Gefühl, dass sie gelöst ist.
mgilson
@mgilson Ich denke unter der gleichen Annahme habe ich nur angenommen, dass es nicht existiert. Ich denke, Sie können nur filterfalseoder etwas verwenden, je nach Anwendungsfall
Jamylak
@ Jamylak - Ja. Mein Hauptproblem ist, dass x > ynicht not x <= yin Python impliziert, weil Sie alles in __lt__und tun können __le__, also warum sollte x not in yimplizieren not x in y(vor allem, weil not ines einen eigenen Bytecode hat?)
mgilson
136

FWIW, Python 3 macht dieses Problem einfach:

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

In Python 2 würden Sie stattdessen ein Listenverständnis verwenden:

>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]
Raymond Hettinger
quelle
+1 Empfehlen Sie die Verwendung von __ne__so im Gegensatz zu partialund ne?
Jamylak
1
@jamylak Ja, es ist schneller, ein bisschen einfacher zu schreiben und ein bisschen klarer.
Raymond Hettinger
Erwägen Sie die Verwendung des operatorModuls.
Rechtsfalte
12
Was ist __ne__?
DrMcCleod
11
@DrMcCleod Der Ausdruck x != yruft intern auf, x.__ne__(y)wobei das ne für "ungleich" steht. Es handelt sich also None.__ne__um eine gebundene Methode, die True zurückgibt, wenn sie mit einem anderen Wert als None aufgerufen wird . Zum Beispiel bm = None.__ne__mit genannten bm(10)Renditen NotImplemented die als wahre Wert und bm(None)kehrt Falsch .
Raymond Hettinger
16

Für Python 2.7 (siehe Raymond's Antwort, für Python 3-Äquivalent):

Wenn Sie wissen möchten, ob etwas "nicht" ist, ist es in Python (und anderen OO-Sprachen) so häufig, dass ich in meiner Common.py (die ich mit "from Common import *" in jedes Modul importiere) folgende Zeilen einfüge:

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

Um keine Elemente aus einer Liste zu entfernen, gehen Sie einfach wie folgt vor:

filter(exists, L)

Ich finde das leichter zu lesen als das entsprechende Listenverständnis (das Raymond als seine Python 2-Version zeigt).

ToolmakerSteve
quelle
Ich würde die Raymonds-Lösung für Python 3 und dann das Listenverständnis für Python 2 bevorzugen. Aber wenn ich diesen Weg gehen müsste, würde ich lieber partial(is_not, None)diese Lösung verwenden. Ich glaube, das wird langsamer (obwohl das nicht zu wichtig ist). Aber mit ein paar Importen von Python-Modulen ist in diesem Fall keine benutzerdefinierte Funktion
erforderlich
16

Mit dem Listenverständnis kann dies wie folgt erfolgen:

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

Der Wert von l ist:

[0, 23, 234, 89, 0, 35, 9]
DotPi
quelle
Diese Lösung ist bereits in der Top-Antwort enthalten, oder fehlt mir etwas?
Qaswed
12

Die Antwort von @jamylak ist ganz nett. Wenn Sie jedoch nicht ein paar Module importieren möchten, um diese einfache Aufgabe zu erledigen, schreiben Sie Ihre eigenen lambdaan Ort und Stelle:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(lambda v: v is not None, L)
[0, 23, 234, 89, 0, 35, 9]
BEIM
quelle
Sie haben meine Lösung offensichtlich nicht richtig gelesen. [x for x in L if x is not None]Der andere Code war nur eine Ergänzung, die ich ausdrücklich angegeben habe und die ich nicht empfehlen würde
jamylak
1
@jamylak - Ich habe es gelesen, aber Sie hatten diese Lösung nicht aufgenommen. - Ich bin mir auch nicht sicher, warum Sie die Antworten der Leute von vor 4-5 Jahren bearbeiten.
AT
5

Iteration vs Space , Nutzung könnte ein Problem sein. In verschiedenen Situationen kann die Profilerstellung entweder "schneller" und / oder "weniger speicherintensiv" sein.

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

Der erste Ansatz (wie auch von @jamylak , @Raymond Hettinger und @Dipto vorgeschlagen ) erstellt eine doppelte Liste im Speicher, was für eine große Liste mit wenigen NoneEinträgen kostspielig sein kann .

Der zweite Ansatz geht die Liste einmal und dann jedes Mal erneut durch, bis a Noneerreicht ist. Dies könnte weniger speicherintensiv sein und die Liste wird mit der Zeit kleiner. Die Verringerung der Listengröße könnte sich für viele NoneEinträge vorne beschleunigen , aber der schlimmste Fall wäre, wenn viele NoneEinträge hinten wären .

Parallelisierung und In-Place-Techniken sind andere Ansätze, aber jeder hat seine eigenen Komplikationen in Python. Wenn Sie die Daten und die Anwendungsfälle zur Laufzeit kennen und das Programm profilieren, können Sie mit intensiven Vorgängen oder großen Datenmengen beginnen.

Die Wahl eines der beiden Ansätze spielt in normalen Situationen wahrscheinlich keine Rolle. Es wird eher eine Präferenz der Notation. In der Tat, unter diesen ungewöhnlichen Umständen numpyoder cythonmöglicherweise lohnende Alternativen, anstatt zu versuchen, Python-Optimierungen zu verwalten.

Kevin
quelle
Kein Fan davon, der ganze Vorteil, den Sie mit dieser Lösung behaupten, ist, dass die Liste möglicherweise so groß ist, dass das Erstellen einer doppelten Liste im Speicher kostspielig sein kann. Dann ist Ihre Lösung noch teurer, da Sie die gesamte Liste durchsuchen L.count(None)und dann .remove(None)mehrmals anrufen , was dazu führt. O(N^2)Die Situation, die Sie lösen möchten, sollte nicht auf diese Weise behandelt werden, sondern die Daten sollten neu strukturiert werden in eine Datenbank oder Datei stattdessen, wenn es so speicherintensiv ist.
Jamylak
@jamylak Richtig, aber nicht alle realen Situationen oder Daten erlauben diese Flexibilität. Zum Beispiel das Pumpen von "alten" Geodaten durch eine einmalige Analyse auf einem System ohne viel Speicher. Dann ist auch die Programmierzeit gegen die Laufzeit zu berücksichtigen. Aufgrund der Zeitersparnis wenden sich die Benutzer häufig an Python. Mit dieser Antwort mache ich darauf aufmerksam, dass das Gedächtnis eine Überlegung wert sein könnte, aber ich stelle am Ende fest, dass es sich meistens um eine individuelle Präferenz in der Notation handelt. Ich weise auch darauf hin, dass es wichtig ist, die Daten zu kennen. O(n^2)ist nur, wenn die gesamte Liste ist None.
Kevin
Wäre interessiert, wenn Sie ein praktisches Beispiel hätten, bei dem diese Antwort die beste Lösung ist. Ich denke eher, dass es in allen Fällen einen besseren Ansatz gibt. Zum Beispiel numpywäre in der Lage, diese Art von Operation in einer optimierten Weise zu handhaben
Jamylak
@ Jamylak Um fair zu sein, ich habe numpyin den letzten Jahren verwendet, aber es ist eine separate Fähigkeit. Wenn Les numpy.arrayanstelle von Python instanziiert wird list, ist L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) wahrscheinlich besser als beide, aber ich kenne die Implementierungsdetails für die Verarbeitung im Vergleich zum Speicher darunter nicht. Es wird mindestens ein Array von Booleschen Werten mit doppelter Länge für die Maske erstellt. Die Syntax eines Vergleichs innerhalb eines Zugriffsoperators (Indexoperators) auf diese Weise ist für mich neu. Diese Diskussion hat mich auch darauf aufmerksam gemacht dtype=object.
Kevin
Diese Diskussion wird jetzt zu abstrakt. Ich glaube nicht, dass Sie mir in Ihrer jahrelangen Erfahrung ein Beispiel aus dem wirklichen Leben geben können, bei dem diese Antwort der richtige Ansatz für die Umstrukturierung der Daten ist, wie ich bereits erwähnt habe.
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
quelle
6
Bitte geben Sie dem OP einige Details und nicht nur einen Code.
Laurent LAPORTE
1
Ich tat. Was denkst du?
med_abidi
Nun, das beantwortet die OP-Frage nicht. Betrachten Sie stattdessen diese Antwort: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE
Ja, du hast recht. Es gab ein Problem mit dem Filterteil.
med_abidi
2

Wenn alles eine Liste von Listen ist, können Sie die Antwort von sir @ Raymond ändern

L = [ [None], [123], [None], [151] ] no_none_val = list(filter(None.__ne__, [x[0] for x in L] ) ) für Python 2 jedoch

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

<< list_indice [0] für Variable in List, wenn Variable nicht None >> ist

Skrmnghrd
quelle
1

Angenommen, die Liste ist wie folgt

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

Dies gibt nur die Elemente zurück, deren bool(item) is True

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

Dies entspricht

print [item for item in iterator if item]

So filtern Sie einfach Keine:

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

Gleichwertig:

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

Um alle Elemente zu erhalten, die als falsch ausgewertet werden

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