0 değerini kaldırmadan Yok değerini listeden kaldır


244

Başladığım kaynak buydu.

Listem

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

Bunu çalıştırdığımda:

L = filter(None, L)

Bu sonuçları alıyorum

[23, 234, 89, 35, 9]

Ama ihtiyacım olan bu değil, gerçekten ihtiyacım olan şey:

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

Çünkü verilerin yüzdeliğini hesaplıyorum ve 0 çok fark yaratıyor.

0 değerini kaldırmadan Yok değerini listeden nasıl kaldırırım?

Yanıtlar:


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]

Sadece eğlenmek için, filterbunu bir kullanmadan yapmak için nasıl adapte olabileceğinizi lambda, (Bu kodu tavsiye etmem - sadece bilimsel amaçlar için)

>>> 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
Daha az zarif filtersürümü: filter(lambda x: x is not None, L)- Sen temizleyecektir lambdakullanarak partialve operator.is_notsanırım, ama o kadar daha temiz muhtemelen liste-comp beri değmez.
mgilson

3
@mgilson Oh vay, var olduğunu bile bilmiyordum is_not! Ben sadece olduğunu düşündüm is_, bunu sadece eğlence için ekleyeceğim
jamylak

@jamylak - Evet. Aslında is_notvar olan ve not_inolmayan beni rahatsız ediyor . Aslında bunun not_insihirli bir yönteme dönüştürülmesi gerektiğini düşünüyorum __not_contains__... bir süre önce sorduğum bir soruya ve bir yanıtlayana yaptığım bir yorum görüyorum ... ve hala çözülmüş gibi hissetmiyorum.
mgilson

mgilson Bence aynı varsayım altında var olmadığını varsaydım Kullanım filterfalsedurumuna bağlı olarak sadece kullanabilirsiniz ya da bir şey sanırım
jamylak 19:13

@jamylak - Evet. Benim asıl sorun olduğunu x > yanlamına gelmez not x <= ysen her şeyi yapabilir, çünkü python __lt__ve __le__, neden gerektiğini x not in yima not x in y(özellikle de not in, bu kendi bayt kodu vardır?)
mgilson

136

FWIW, Python 3 bu sorunu kolaylaştırır:

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

Python 2'de, bir liste kavrama kullanırsınız:

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

+1 ve __ne__yerine bunun gibi kullanımını tavsiye eder misiniz ? partialne
jamylak

1
@jamylak Evet, daha hızlı, yazması biraz daha kolay ve biraz daha net.
Raymond Hettinger

operatorModülü kullanmayı düşünün .
rightfold

12
Nedir __ne__?
DrMcCleod

11
@DrMcCleod ifadesi x != ydahili aramalar x.__ne__(y)nerede ne "eşit değil" anlamına gelir. Yani, Hiçbiri dışında herhangi bir değerle çağrıldığında TrueNone.__ne__ döndüren bağlı bir yöntemdir . Örneğin, birlikte denilen getiriler NotImplemented hangi gerçek değeri ve aynı getiri Yanlış . bm = None.__ne__bm(10)bm(None)
Raymond Hettinger

17

Liste kavrayışı kullanılarak bu aşağıdaki gibi yapılabilir:

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

L değeri:

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

Bu çözüm en iyi yanıtta zaten var ya da bir şey mi eksik?
Qaswed

16

Python 2.7 için (Python 3 eşdeğeri için Raymond'un cevabına bakınız):

Bir şey "Hiçbiri" olup olmadığını bilmek isteyen python (ve diğer OO dillerinde) çok yaygın, benim Common.py (ki ben her modül için "Ortak ithalat *" ile ithal), ben bu satırları dahil:

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

Ardından, Yok öğelerini bir listeden kaldırmak için şunları yapmanız yeterlidir:

filter(exists, L)

Bunu okumak için, karşılık gelen liste kavrayışından (Raymond'un Python 2 sürümü olarak gösterdiği) daha kolay buluyorum.


Python 3 için Raymonds çözümünü, sonra da Python 2 için liste kavrayışını tercih ederim partial(is_not, None). Bunun daha yavaş olacağına inanıyorum (bu çok önemli olmasa da). Ancak birkaç python modülü ithalatı ile, bu durumda özel tanımlanmış bir işleve gerek yok
jamylak

12

@jamylak cevabı oldukça güzel, ancak sadece bu basit görevi yapmak için birkaç modülü içe aktarmak istemiyorsanız, kendi lambdayerinde yazın:

>>> 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çıkçası benim çözüm doğru okumadım hangi [x for x in L if x is not None]diğer kod sadece ben açıkça tavsiye etmem belirtilen bir ek oldu
jamylak

1
@jamylak - Okudum, ama siz bu çözümü eklememiştiniz. - Ayrıca insanların yanıtlarını neden 4-5 yıl önce düzenlediğinizden de emin değilim.
AT

5

Yineleme ve Uzay karşılaştırması , kullanım bir sorun olabilir. Farklı durumlarda profil oluşturma "daha hızlı" ve / veya "daha az bellek" yoğun olarak gösterilebilir.

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

İlk (aynı zamanda önerdiği yaklaşım @jamylak , @Raymond Hettinger ve @Dipto ) birkaç ile büyük bir listesi için masraflı olabilir bellekte ikinci bir liste oluşturur Nonegirdileri.

İkinci yaklaşım kez listede geçer ve sonra tekrar bir kadar her zaman Noneulaşılır. Bu daha az bellek yoğun olabilir ve liste gittikçe küçülür. Liste boyutundaki azalma None, öndeki çok sayıda giriş için hızlanabilir, ancak en kötü durum, çok sayıda Nonegiriş arkada olsaydı olurdu .

Paralelleştirme ve yerinde teknikler diğer yaklaşımlardır, ancak her birinin Python'da kendi komplikasyonları vardır. Verileri ve çalışma zamanı kullanım durumlarını bilmek, aynı zamanda programın profilini çıkarmak, yoğun işlemler veya büyük veriler için nereden başlayacağınızdır.

Her iki yaklaşımdan birini seçmek muhtemelen ortak durumlarda önemli olmayacaktır. Daha çok bir gösterim tercihi haline gelir. Aslında, bu nadir durumlarda, numpyveya cythonPython optimizasyonlarını mikromanide etmek yerine alternatifler olabilir.


Bunun bir hayranı değil, bu çözümle iddia ettiğiniz tüm avantaj, listenin bellekte yinelenen liste oluşturmanın pahalı olabileceği kadar büyük olabileceğidir. Peki o zaman çözüm olacaktır daha masraflı için tüm listeyi taramak çünkü L.count(None)sonra aradığınız .remove(None)bu kılan birden çok kez O(N^2)bu şekilde ele alınması gerektiğini çözmeye çalışıyoruz durum, veri yeniden yapılandırılmalıdır bu bellek yoğun ise bir veritabanı veya dosya içine.
jamylak

@jamylak Doğru, ancak tüm gerçek dünya durumları veya verileri bu esnekliğe izin vermez. Örneğin, çok fazla belleğe sahip olmayan bir sistemdeki bir defalık analiz yoluyla "eski" coğrafi uzamsal verilerin pompalanması. Sonra da dikkate almak için çalışma zamanı vs programlama zamanı vardır. İnsanlar genellikle geliştirme süresindeki tasarruflar nedeniyle Python'a yönelirler. Bu cevapla, belleğin dikkate almaya değer olabileceğine dikkat çekiyorum, ama sonunda bunun çoğunlukla gösterimde bireysel tercih olduğunu belirtiyorum. Ayrıca verilerin bilinmesinin önemli olduğuna da dikkat çekiyorum. O(n^2)yalnızca tüm liste olduğunda None.
Kevin

Bu cevabın en iyi çözüm olduğu pratik bir örneğiniz olsaydı ilgilenirim, her durumda daha iyi bir yaklaşım olacağını düşünüyorum. Örneğin numpy, bu tür operasyonları daha optimize bir şekilde idare edebilecektir
Jamylak

@jamylak Adil olmak gerekirse numpy, son yıllarda kullanıyorum , ama ayrı bir yetenek. Eğer Lbir şekilde örneği numpy.arrayyerine Python list, daha sonra L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) muhtemelen daha iyi ikisinden de, ama hafıza ve alt kısımda vs işlenmesi için uygulama ayrıntıları bilmiyorum. En azından maske için yinelenen uzunlukta bir boole dizisi oluşturur. Bir erişim (dizin) operatörü içindeki bir karşılaştırmanın sözdizimi, bu şekilde benim için yeni. Bu tartışma da dikkatimi çekti dtype=object.
Kevin

Bu tartışma şimdi çok soyutlaşıyor, yılların tecrübesinde bana bu cevabın daha önce bahsettiğim gibi verileri yeniden yapılandırmak için doğru bir yaklaşım olduğu bir gerçek yaşam örneği verebileceğinizi sanmıyorum.
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
Lütfen, OP'ye sadece bir kod değil, bazı detay bilgileri verin.
Laurent LAPORTE

1
Yaptım. Ne düşündüğünü?
med_abidi

Bu OP sorusuna cevap vermiyor. Bunun yerine bu yanıtı düşünün: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE

Evet haklısın. Filtre kısmi ile ilgili bir sorun vardı.
med_abidi

2

Hepsi bir liste listesiyse, sir @ Raymond'un cevabını değiştirebilirsiniz.

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

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

<< list_indice [0] Değişken Yok ise Listedeki değişken için >>


1

Listenin aşağıdaki gibi olduğunu söyle

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

Bu yalnızca şu öğeleri döndürür: bool(item) is True

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

Bu şuna eşdeğerdir:

print [item for item in iterator if item]

Yalnızca Hiçbiri'ni filtrelemek için:

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

Eşittir:

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

Değerlendirilen tüm öğeleri Yanlış olarak almak için

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.