Jawaban:
Python 2.X
dict((k, v) for k, v in metadata.iteritems() if v)
Python 2.7 - 3.X
{k: v for k, v in metadata.items() if v is not None}
Perhatikan bahwa semua kunci Anda memiliki nilai. Hanya saja beberapa dari nilai tersebut adalah string kosong. Tidak ada yang namanya kunci dalam sebuah dict tanpa nilai; jika tidak memiliki nilai, tidak akan ada di dict.
.items()
.
{k: v for k, v in metadata.items() if v is not None}
Ini bisa menjadi lebih pendek dari solusi BrenBarn (dan saya pikir lebih mudah dibaca)
{k: v for k, v in metadata.items() if v}
Diuji dengan Python 2.7.3.
... if v!=None
seperti ini: {k: v for k, v in metadata.items() if v!=None}
Jika Anda benar-benar perlu mengubah kamus asli:
empty_keys = [k for k,v in metadata.iteritems() if not v]
for k in empty_keys:
del metadata[k]
Perhatikan bahwa kita harus membuat daftar kunci kosong karena kita tidak dapat mengubah kamus saat mengulanginya (seperti yang mungkin telah Anda ketahui). Ini lebih murah (dari segi memori) daripada membuat kamus baru, kecuali jika ada banyak entri dengan nilai kosong.
.iteritems()
dengan .items()
, pertama tidak bekerja lagi dalam versi Python terbaru.
Solusi BrenBarn ideal (dan pythonic, saya bisa menambahkan). Berikut adalah solusi lain (fp), namun:
from operator import itemgetter
dict(filter(itemgetter(1), metadata.items()))
Jika Anda menginginkan pendekatan berfitur lengkap namun ringkas untuk menangani struktur data dunia nyata yang sering bersarang, dan bahkan dapat berisi siklus, saya sarankan untuk melihat utilitas pemetaan ulang dari paket utilitas boltons .
Setelah pip install boltons
atau menyalin iterutils.py ke dalam proyek Anda, lakukan saja:
from boltons.iterutils import remap
drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)
Halaman ini memiliki lebih banyak contoh, termasuk yang bekerja dengan objek yang jauh lebih besar dari API Github.
Ini murni-Python, jadi berfungsi di mana-mana, dan sepenuhnya diuji dengan Python 2.7 dan 3.3+. Yang terbaik dari semuanya, saya menulisnya persis untuk kasus seperti ini, jadi jika Anda menemukan kasus yang tidak tertangani, Anda dapat mengganggu saya untuk memperbaikinya di sini .
Berdasarkan solusi Ryan , jika Anda juga memiliki daftar dan kamus bertingkat:
Untuk Python 2:
def remove_empty_from_dict(d):
if type(d) is dict:
return dict((k, remove_empty_from_dict(v)) for k, v in d.iteritems() if v and remove_empty_from_dict(v))
elif type(d) is list:
return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)]
else:
return d
Untuk Python 3:
def remove_empty_from_dict(d):
if type(d) is dict:
return dict((k, remove_empty_from_dict(v)) for k, v in d.items() if v and remove_empty_from_dict(v))
elif type(d) is list:
return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)]
else:
return d
d = { "things": [{ "name": "" }] }
Jika Anda memiliki kamus bertingkat, dan Anda ingin ini berfungsi bahkan untuk sub-elemen kosong, Anda dapat menggunakan varian rekursif dari saran BrenBarn:
def scrub_dict(d):
if type(d) is dict:
return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v))
else:
return d
items()
alih-alih iteritems()
untuk Python 3
### example01 -------------------
mydict = { "alpha":0,
"bravo":"0",
"charlie":"three",
"delta":[],
"echo":False,
"foxy":"False",
"golf":"",
"hotel":" ",
}
newdict = dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(vdata) ])
print newdict
### result01 -------------------
result01 ='''
{'foxy': 'False', 'charlie': 'three', 'bravo': '0'}
'''
### example02 -------------------
mydict = { "alpha":0,
"bravo":"0",
"charlie":"three",
"delta":[],
"echo":False,
"foxy":"False",
"golf":"",
"hotel":" ",
}
newdict = dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(str(vdata).strip()) ])
print newdict
### result02 -------------------
result02 ='''
{'alpha': 0,
'bravo': '0',
'charlie': 'three',
'delta': [],
'echo': False,
'foxy': 'False'
}
'''
Untuk python 3
dict((k, v) for k, v in metadata.items() if v)
Membangun jawaban dari patriciasz dan nneonneo , dan memperhitungkan kemungkinan bahwa Anda mungkin ingin menghapus kunci yang hanya memiliki hal-hal palsu tertentu (misalnya ''
) tetapi tidak yang lain (misalnya 0
), atau mungkin Anda bahkan ingin memasukkan beberapa hal yang benar (misalnya 'SPAM'
) , lalu Anda dapat membuat daftar target yang sangat spesifik:
unwanted = ['', u'', None, False, [], 'SPAM']
Sayangnya, ini tidak cukup berhasil, karena misalnya 0 in unwanted
mengevaluasi ke True
. Kita perlu membedakan antara 0
dan hal-hal palsu lainnya, jadi kita harus menggunakan is
:
any([0 is i for i in unwanted])
... mengevaluasi ke False
.
Sekarang gunakan untuk del
hal yang tidak diinginkan:
unwanted_keys = [k for k, v in metadata.items() if any([v is i for i in unwanted])]
for k in unwanted_keys: del metadata[k]
Jika Anda menginginkan kamus baru, alih-alih mengubah metadata
di tempat:
newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])}
[]
Saya membaca semua balasan di utas ini dan beberapa juga merujuk ke utas ini: Hapus dicts kosong di kamus bersarang dengan fungsi rekursif
Saya awalnya menggunakan solusi di sini dan itu berfungsi dengan baik:
Percobaan 1: Terlalu Panas (tidak berkinerja baik atau tidak terbukti masa depan) :
def scrub_dict(d):
if type(d) is dict:
return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v))
else:
return d
Tetapi beberapa masalah kinerja dan kompatibilitas diangkat di dunia Python 2.7:
isinstance
sebagai gantitype
for
lingkaran untuk efisiensiitems
bukaniteritems
Percobaan 2: Terlalu Dingin (Kurang Memoisasi) :
def scrub_dict(d):
new_dict = {}
for k, v in d.items():
if isinstance(v,dict):
v = scrub_dict(v)
if not v in (u'', None, {}):
new_dict[k] = v
return new_dict
DOH! Ini tidak rekursif dan sama sekali tidak memoizant.
Percobaan 3: Just Right (sejauh ini) :
def scrub_dict(d):
new_dict = {}
for k, v in d.items():
if isinstance(v,dict):
v = scrub_dict(v)
if not v in (u'', None, {}):
new_dict[k] = v
return new_dict
if isinstance(v, list):
, yang menghapus daftar menggunakan scrub_dict(d)
implementasi asli . @staticmethod
def scrub_dict(d):
new_dict = {}
for k, v in d.items():
if isinstance(v, dict):
v = scrub_dict(v)
if isinstance(v, list):
v = scrub_list(v)
if not v in (u'', None, {}):
new_dict[k] = v
return new_dict
@staticmethod
def scrub_list(d):
scrubbed_list = []
for i in d:
if isinstance(i, dict):
i = scrub_dict(i)
scrubbed_list.append(i)
return scrubbed_list
Cara alternatif untuk melakukan ini adalah dengan menggunakan pemahaman kamus. Ini harus kompatibel dengan2.7+
result = {
key: value for key, value in
{"foo": "bar", "lorem": None}.items()
if value
}
Berikut adalah opsi jika Anda menggunakan pandas
:
import pandas as pd
d = dict.fromkeys(['a', 'b', 'c', 'd'])
d['b'] = 'not null'
d['c'] = '' # empty string
print(d)
# convert `dict` to `Series` and replace any blank strings with `None`;
# use the `.dropna()` method and
# then convert back to a `dict`
d_ = pd.Series(d).replace('', None).dropna().to_dict()
print(d_)
Beberapa Metode yang disebutkan di atas mengabaikan jika ada bilangan bulat dan mengambang dengan nilai 0 & 0,0
Jika seseorang ingin menghindari hal di atas dapat menggunakan kode di bawah ini (menghapus string kosong dan nilai None dari kamus bersarang dan daftar bersarang):
def remove_empty_from_dict(d):
if type(d) is dict:
_temp = {}
for k,v in d.items():
if v == None or v == "":
pass
elif type(v) is int or type(v) is float:
_temp[k] = remove_empty_from_dict(v)
elif (v or remove_empty_from_dict(v)):
_temp[k] = remove_empty_from_dict(v)
return _temp
elif type(d) is list:
return [remove_empty_from_dict(v) for v in d if( (str(v).strip() or str(remove_empty_from_dict(v)).strip()) and (v != None or remove_empty_from_dict(v) != None))]
else:
return d
"Karena saat ini saya juga menulis aplikasi desktop untuk pekerjaan saya dengan Python, saya menemukan di aplikasi entri data ketika ada banyak entri dan ada beberapa yang tidak wajib sehingga pengguna dapat membiarkannya kosong, untuk tujuan validasi, mudah untuk diambil semua entri dan kemudian buang kunci kosong atau nilai kamus Jadi kode saya di atas menunjukkan bagaimana kita dapat dengan mudah mengeluarkannya, menggunakan pemahaman kamus dan menyimpan elemen nilai kamus yang tidak kosong.Saya menggunakan Python 3.8.3
data = {'':'', '20':'', '50':'', '100':'1.1', '200':'1.2'}
dic = {key:value for key,value in data.items() if value != ''}
print(dic)
{'100': '1.1', '200': '1.2'}
In [7]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
...: dic = {k: v for k, v in dic.items() if v is not None}
1000000 loops, best of 7: 375 ns per loop
In [8]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
...: dic = dict((k, v) for k, v in dic.items() if v is not None)
1000000 loops, best of 7: 681 ns per loop
In [10]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
...: for k, v in dic.items():
...: if v is None:
...: del dic[k]
...:
10000000 loops, best of 7: 160 ns per loop
jadi loop dan delete adalah yang tercepat di 160ns, pemahaman daftar setengah lambat di ~ 375ns dan dengan panggilan ke dict()
setengah lambat lagi ~ 680ns.
Membungkus 3 menjadi fungsi membawanya kembali ke sekitar 275ns. Juga bagi saya PyPy sekitar dua kali lebih cepat dari python neet.
list(dic.items())
di py 3. Dict pemahaman ftw lalu? del masih tampak lebih cepat untuk rasio rendah nilai Null / kosong. Saya kira membangun daftar itu sama buruknya dengan konsumsi memori daripada hanya membuat ulang dict.