usuń Brak wartości z listy bez usuwania wartości 0


244

To było moje źródło, od którego zacząłem.

Moja lista

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

Kiedy uruchomię to:

L = filter(None, L)

Dostaję te wyniki

[23, 234, 89, 35, 9]

Ale nie tego potrzebuję, tak naprawdę potrzebuję:

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

Ponieważ obliczam percentyl danych, a 0 robi dużą różnicę.

Jak usunąć wartość None z listy bez usuwania wartości 0?

Odpowiedzi:


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]

Dla zabawy, oto jak możesz się dostosować, filteraby to zrobić bez użycia lambda, (nie poleciłbym tego kodu - to tylko do celów naukowych)

>>> 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
Mniej elegancka filterwersja: filter(lambda x: x is not None, L)- Można się pozbyć lambdaużywania partiali operator.is_notmyślę, ale chyba nie warto, ponieważ lista-kompat jest o wiele czystsza.
mgilson,

3
@mgilson Oh wow, nawet nie wiedziałem, że is_notistnieje! Myślałem, że to tylko is_, dodam to dla zabawy
jamylak

@jamylak - Tak. W rzeczywistości przeszkadza mi to, że is_notistnieje i not_innie istnieje. Myślę, że not_innależy to zmienić w magiczną metodę __not_contains__... patrz pytanie, które zadałem jakiś czas temu i komentarz, który skierowałem do osoby udzielającej odpowiedzi ... i nadal nie czuję, że to zostało rozwiązane.
mgilson,

@mgilson Myślę, że przy tym samym założeniu po prostu założyłem, że nie istnieje. Myślę, że możesz po prostu użyć filterfalselub coś w zależności od przypadku użycia
jamylak 19.04.13

@jamylak - Tak. Moim głównym problemem jest tox > y nie oznacza to not x <= yw Pythonie, ponieważ możesz zrobić wszystko w, __lt__a __le__więc dlaczego miałbyś x not in ysugerować not x in y(zwłaszcza, że not inma swój własny kod bajtowy?)
mgilson 19.04.2013

136

FWIW, Python 3 ułatwia ten problem:

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

W Pythonie 2 zamiast tego użyłbyś rozumienia listy:

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

+1 Czy polecasz użycie __ne__tego w przeciwieństwie do partiali ne?
jamylak

1
@jamylak Tak, jest szybszy, nieco łatwiejszy do napisania i bardziej przejrzysty.
Raymond Hettinger

Rozważ użycie operatormodułu.
prawej

12
Co to jest __ne__?
DrMcCleod

11
@DrMcCleod Wyrażenie x != ywewnętrznie wywołuje x.__ne__(y)tam, gdzie ne oznacza „nie równy”. Tak, None.__ne__jest związany metoda, która zwraca Prawda , gdy wywołana z dowolnego wartość inną niż None . Na przykład bm = None.__ne__wywoływany ze bm(10)zwrotami NotImplemented, który jako wartość true, i bm(None)zwraca False .
Raymond Hettinger

17

Używając listy, można to zrobić w następujący sposób:

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

Wartość l wynosi:

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

To rozwiązanie znajduje się już w górnej odpowiedzi, czy coś mi brakuje?
Qaswed

16

W przypadku Python 2.7 (patrz odpowiedź Raymonda, odpowiednik w Python 3):

Chcąc wiedzieć, czy coś „nie jest Żaden” jest tak powszechne w pythonie (i innych językach OO), że w moim pliku Common.py (który importuję do każdego modułu za pomocą „ze wspólnego importu *”), dołączam następujące wiersze:

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

Następnie, aby usunąć Brak elementów z listy, po prostu wykonaj:

filter(exists, L)

Uważam to za łatwiejsze do odczytania niż odpowiednie rozumienie listy (którą pokazuje Raymond jako swoją wersję Python 2).


Wolę rozwiązanie Raymonds dla Pythona 3, a następnie zrozumienie listy dla Pythona 2. Ale gdybym musiał iść tą drogą, wolałbym partial(is_not, None)to rozwiązanie. Wierzę, że będzie wolniej (choć nie jest to zbyt ważne). Ale z kilkoma importami modułów Pythona, w tym przypadku nie ma potrzeby definiowania niestandardowej funkcji
jamylak

12

Odpowiedź @jamylak jest całkiem przyjemna, jednak jeśli nie chcesz zaimportować kilku modułów tylko do wykonania tego prostego zadania, napisz własne lambdaw miejscu:

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

Najwyraźniej nie przeczytałeś mojego rozwiązania poprawnie, ponieważ [x for x in L if x is not None]drugi kod był tylko dodatkiem, który wyraźnie powiedziałem, że nie polecam
jamylak

1
@jamylak - Przeczytałem to, ale nie uwzględniłeś tego rozwiązania. - Nie jestem również pewien, dlaczego edytujesz odpowiedzi ludzi sprzed 4-5 lat.
AT

5

Iteracja a przestrzeń kosmiczna , użycie może być problemem. W różnych sytuacjach profilowanie może wykazywać „szybsze” i / lub „mniejsze zużycie pamięci”.

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

Pierwsze podejście (jak również sugerowane przez @jamylak , @Raymond Hettinger i @Dipto ) tworzy jego duplikat listy w pamięci, która może być kosztowne dla dużej listy z kilku Nonewpisów.

Drugie podejście przechodzi listy raz, a potem jeszcze raz za każdym razem, dopóki nie Nonezostanie osiągnięta. Może to wymagać mniejszej ilości pamięci, a lista będzie się zmniejszać. Zmniejszenie rozmiaru listy może przyspieszyć wiele Nonewpisów z przodu, ale najgorszym przypadku byłoby, gdyby wiele Nonewpisów było z tyłu.

Techniki równoległe i lokalne są innymi podejściami, ale każda z nich ma swoje własne komplikacje w Pythonie. Znajomość danych i przypadków użycia w środowisku wykonawczym, a także profilowanie programu to miejsce, w którym można rozpocząć intensywne operacje lub duże dane.

Wybór jednego z podejść prawdopodobnie nie będzie miał znaczenia w typowych sytuacjach. Staje się bardziej preferencją zapisu. W rzeczywistości w tych rzadkich okolicznościach numpylub cythonmogą być wartościowymi alternatywami zamiast próbować mikromanalizować optymalizacje Pythona.


Nie jestem fanem tego, cała ta korzyść, którą twierdzisz w tym rozwiązaniu, polega na tym, że lista może być tak duża, że zbudowanie zduplikowanej listy w pamięci może być kosztowne. Cóż, wtedy Twoje rozwiązanie będzie jeszcze bardziej kosztowne, ponieważ skanujesz całą listę, L.count(None)a następnie dzwonisz .remove(None)wiele razy, co powoduje, że O(N^2)sytuacja, którą próbujesz rozwiązać, nie powinna być rozwiązana w ten sposób, dane powinny zostać zrestrukturyzowane zamiast tego do bazy danych lub pliku, jeśli zajmuje dużo pamięci.
jamylak

@jamylak To prawda, ale nie wszystkie rzeczywiste sytuacje lub dane pozwalają na taką elastyczność. Na przykład pompowanie „starszych” danych geoprzestrzennych poprzez jednorazową analizę w systemie bez dużej ilości pamięci. Następnie należy wziąć pod uwagę czas programowania i czas działania. Ludzie często zwracają się do Pythona ze względu na oszczędność czasu programowania. Tą odpowiedzią zwracam uwagę na fakt, że pamięć mogłaby być warta rozważenia, ale na koniec stwierdzam, że jest to przede wszystkim indywidualna preferencja w notacji. Zwracam również uwagę, że znajomość danych jest ważna. O(n^2)jest tylko wtedy, gdy cała lista jest None.
Kevin

Byłbym zainteresowany, gdybyś miał praktyczny przykład, w którym ta odpowiedź jest najlepszym rozwiązaniem, myślę, że we wszystkich przypadkach byłoby lepsze podejście. Na przykład numpybyłby w stanie poradzić sobie z tego typu operacjami w bardziej zoptymalizowany sposób
jamylak

@jamylak Szczerze mówiąc, używałem numpyw ostatnich latach, ale jest to osobna umiejętność. Jeśli Ljest tworzony jako numpy.arrayzamiast Pythona list, to L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) jest prawdopodobnie lepszy niż którykolwiek z nich, ale nie znam szczegółów implementacji przetwarzania względem pamięci poniżej. Co najmniej tworzy tablicę duplikatów wartości logicznych dla maski. W ten sposób składnia porównania wewnątrz operatora dostępu (indeksu) jest dla mnie nowa. Ta dyskusja zwróciła również moją uwagę dtype=object.
Kevin

Ta dyskusja robi się teraz zbyt abstrakcyjna, nie sądzę, żebyś był w stanie podać jeden prawdziwy przykład z lat doświadczeń, w którym ta odpowiedź jest poprawnym podejściem do restrukturyzacji danych, jak wspomniałem wcześniej.
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
Proszę podać OP kilka szczegółowych informacji, a nie tylko kod.
Laurent LAPORTE,

1
Zrobiłem. Co myślisz?
med_abidi

Cóż, to nie odpowiada na pytanie OP. Zamiast tego rozważ tę odpowiedź: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE

Tak masz rację. Wystąpił problem z częściowym filtrem.
med_abidi

2

Jeśli jest to tylko lista list, możesz zmodyfikować odpowiedź sir @ Raymonda

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

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

<< list_indice [0] dla zmiennej na liście, jeśli zmienna nie jest żadna >>


1

Powiedzmy, że lista jest jak poniżej

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

Zwróci tylko te przedmioty, których bool(item) is True

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

Jest to równoważne z

print [item for item in iterator if item]

Aby po prostu filtrować Brak:

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

Równoważny:

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

Aby uzyskać wszystkie elementy, które oceniają na False

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.