hapus Tidak ada nilai dari daftar tanpa menghapus nilai 0


244

Ini adalah sumber yang saya mulai.

Daftarku

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

Ketika saya menjalankan ini:

L = filter(None, L)

Saya mendapatkan hasil ini

[23, 234, 89, 35, 9]

Tapi ini bukan yang saya butuhkan, yang saya butuhkan adalah:

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

Karena saya sedang menghitung persentil dari data dan 0 membuat banyak perbedaan.

Bagaimana cara menghapus nilai None dari daftar tanpa menghapus nilai 0?

Jawaban:


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]

Hanya untuk bersenang-senang, inilah cara Anda dapat beradaptasi filteruntuk melakukan ini tanpa menggunakan lambda, (Saya tidak akan merekomendasikan kode ini - ini hanya untuk tujuan ilmiah)

>>> 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
Versi yang kurang elegan filter: filter(lambda x: x is not None, L)- Anda bisa menghilangkan lambdapenggunaan partialdan operator.is_notsaya pikir, tapi mungkin tidak sepadan karena list-comp jauh lebih bersih.
mgilson

3
@mgilson Oh wow aku bahkan tidak tahu is_notada! Saya pikir itu hanya is_, saya akan menambahkannya hanya untuk bersenang
jamylak

@ Jamesylak - Ya. Sebenarnya mengganggu saya yang is_notada dan not_intidak ada. Saya benar-benar berpikir bahwa itu not_inharus diubah menjadi metode ajaib __not_contains__... lihat pertanyaan yang saya ajukan beberapa waktu lalu dan komentar yang saya buat untuk seorang penjawab ... dan masih tidak merasa seperti itu diselesaikan.
mgilson

@ Mcgson Saya pikir di bawah asumsi yang sama saya hanya berasumsi itu tidak ada. Saya kira Anda hanya dapat menggunakan filterfalseatau sesuatu tergantung pada kasus penggunaan
jamylak

@ Jamesylak - Ya. Masalah utama saya adalah bahwa x > ytidak menyiratkan not x <= ydalam python karena Anda dapat melakukan apa pun di , __lt__dan __le__mengapa harus x not in ymenyiratkan not x in y(terutama karena not inmemiliki bytecode sendiri?)
mgilson

136

FWIW, Python 3 membuat masalah ini mudah:

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

Di Python 2, Anda akan menggunakan pemahaman daftar sebagai gantinya:

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

+1 Apakah Anda merekomendasikan penggunaan __ne__seperti itu sebagai lawan dari partialdan ne?
jamylak

1
@ Jakamak Ya, lebih cepat, sedikit lebih mudah untuk menulis, dan sedikit lebih jelas
Raymond Hettinger

Pertimbangkan untuk menggunakan operatormodul ini.
sayap kanan

12
Apa __ne__?
DrMcCleod

11
@DrMcCleod Ekspresi secara x != yinternal memanggil di x.__ne__(y)mana ne adalah "tidak sama". Jadi, None.__ne__adalah metode terikat yang mengembalikan Benar ketika dipanggil dengan nilai apa pun selain Tidak Ada . Misalnya, bm = None.__ne__dipanggil dengan bm(10)pengembalian NotImplemented yang sebagai nilai benar, dan bm(None)mengembalikan False .
Raymond Hettinger

17

Menggunakan daftar pemahaman ini dapat dilakukan sebagai berikut:

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

Nilai l adalah:

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

Solusi ini sudah ditemukan di jawaban atas, atau saya kehilangan sesuatu?
Qaswed

16

Untuk Python 2.7 (Lihat jawaban Raymond, untuk Python 3 yang setara):

Ingin tahu apakah sesuatu "bukan Tidak Ada" begitu umum di python (dan bahasa OO lainnya), sehingga dalam Common.py saya (yang saya impor ke setiap modul dengan "from Common import *"), saya menyertakan baris-baris ini:

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

Kemudian untuk menghapus Tidak ada elemen dari daftar, cukup lakukan:

filter(exists, L)

Saya menemukan ini lebih mudah dibaca, daripada pemahaman daftar terkait (yang menunjukkan Raymond, sebagai versi Python 2-nya).


Saya lebih suka solusi Raymonds untuk Python 3, dan kemudian daftar pemahaman untuk Python 2. Tetapi jika saya harus pergi rute ini, saya lebih suka partial(is_not, None)solusi ini. Saya percaya ini akan lebih lambat (walaupun itu tidak terlalu penting). Tetapi dengan beberapa impor modul python, tidak perlu untuk fungsi yang didefinisikan khusus dalam kasus ini
jamylak

12

@jamylak jawaban cukup bagus, namun jika Anda tidak ingin mengimpor beberapa modul hanya untuk melakukan tugas sederhana ini, tulis sendiri lambdadi tempat:

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

Anda jelas tidak membaca solusi saya dengan benar yang merupakan [x for x in L if x is not None]kode lain hanya tambahan saya secara eksplisit menyatakan saya tidak akan merekomendasikan
jamylak

1
@ jamylak - Saya memang membacanya, tetapi Anda belum memasukkan solusi ini. - Juga tidak yakin mengapa Anda mengedit jawaban orang dari 4-5 tahun yang lalu.
PADA

5

Iterasi vs Space , penggunaan bisa menjadi masalah. Dalam situasi yang berbeda, profil mungkin menunjukkan menjadi "lebih cepat" dan / atau "kurang memori" intensif.

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

The pertama pendekatan (seperti yang juga disarankan oleh @jamylak , @Raymond Hettinger , dan @Dipto ) menciptakan duplikat daftar di memori, yang bisa mahal untuk daftar besar dengan beberapa Noneentri.

The kedua pendekatan melewati daftar sekali, dan sekali lagi setiap kali sampai Nonetercapai. Ini bisa kurang intensif memori, dan daftar akan semakin kecil seiring berjalannya waktu. Penurunan ukuran daftar bisa mempercepat untuk banyak Noneentri di depan, tetapi kasus terburuk adalah jika banyak Noneentri di belakang.

Paralelisasi dan teknik in-place adalah pendekatan lain, tetapi masing-masing memiliki komplikasinya sendiri dalam Python. Mengetahui data dan kasus penggunaan runtime, serta membuat profil program adalah tempat untuk memulai operasi intensif atau data besar.

Memilih pendekatan mana pun mungkin tidak masalah dalam situasi umum. Itu menjadi lebih dari preferensi notasi. Bahkan, dalam keadaan yang tidak biasa itu, numpyatau cythonmungkin merupakan alternatif yang bermanfaat daripada mencoba untuk mengoptimalkan mikro Python.


Sama sekali bukan penggemar ini, seluruh keuntungan yang Anda klaim dengan solusi ini adalah bahwa daftarnya mungkin sangat besar sehingga membuat daftar duplikat dalam memori bisa mahal. Maka solusi Anda akan menjadi lebih mahal karena Anda memindai seluruh daftar L.count(None)dan kemudian Anda menelepon .remove(None)beberapa kali yang membuat ini O(N^2). Situasi yang Anda coba selesaikan tidak boleh ditangani dengan cara ini, data harus direstrukturisasi. ke dalam Database atau file sebagai gantinya jika itu intensif memori.
jamylak

@ jamylak Benar, tetapi tidak semua situasi atau data dunia nyata memungkinkan fleksibilitas itu. Misalnya, memompa data geospasial "warisan" melalui analisis satu kali pada sistem tanpa banyak memori. Lalu ada juga waktu pemrograman vs runtime untuk dipertimbangkan. Orang sering beralih ke Python karena penghematan waktu pengembangan. Dengan jawaban ini, saya membawa perhatian pada fakta bahwa ingatan bisa dipertimbangkan, tetapi saya menyatakan pada akhirnya bahwa sebagian besar preferensi individu dalam notasi. Saya juga menunjukkan bahwa mengetahui data itu penting. O(n^2)hanya ketika seluruh daftar None.
Kevin

Akan tertarik jika Anda memiliki contoh praktis di mana jawaban ini adalah solusi terbaik, saya cenderung berpikir bahwa akan ada pendekatan yang lebih baik dalam semua kasus. Misalnya numpyakan dapat menangani jenis operasi ini dengan cara yang lebih optimal
jamylak

@ jamylak Agar adil, saya telah menggunakan numpydalam beberapa tahun terakhir, tetapi itu adalah keterampilan yang terpisah. Jika Ldipakai sebagai numpy.arraypengganti Python list, maka L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) mungkin lebih baik daripada keduanya, tapi saya tidak tahu detail implementasi untuk memproses vs memori di bawahnya. Setidaknya membuat array panjang boolean duplikat untuk topeng. Sintaks perbandingan di dalam operator akses (indeks), dengan cara itu, baru bagi saya. Diskusi ini juga menarik perhatian saya dtype=object.
Kevin

Diskusi ini menjadi terlalu abstrak sekarang, saya tidak berpikir Anda akan bisa memberi saya satu contoh nyata dalam pengalaman Anda bertahun-tahun di mana jawaban ini adalah pendekatan yang tepat untuk merestrukturisasi data seperti yang saya sebutkan sebelumnya.
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
Tolong, berikan beberapa detail informasi ke OP, dan bukan hanya kode.
Laurent LAPORTE

1
Aku melakukannya. Apa yang Anda pikirkan?
med_abidi

Nah, ini tidak menjawab pertanyaan OP. Pertimbangkan jawaban ini sebagai gantinya: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE

Ya kamu benar. Ada masalah dengan sebagian filter.
med_abidi

2

Jika semuanya daftar daftar, Anda dapat mengubah jawaban sir @ Raymond

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

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

<< list_indice [0] untuk variabel dalam Daftar jika variabel tidak ada >>


1

Katakanlah daftarnya seperti di bawah ini

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

Ini hanya akan mengembalikan barang-barang yang bool(item) is True

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

Ini setara dengan

print [item for item in iterator if item]

Untuk hanya memfilter Tidak Ada:

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

Setara dengan:

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

Untuk mendapatkan semua item yang dievaluasi menjadi False

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.