Câu trả lời:
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}
Lưu ý rằng tất cả các khóa của bạn đều có giá trị. Chỉ là một số giá trị trong số đó là chuỗi trống. Không có cái gọi là khóa trong một mệnh đề mà không có giá trị; nếu nó không có giá trị, nó sẽ không ở trong dict.
.items()
.
{k: v for k, v in metadata.items() if v is not None}
Nó có thể ngắn hơn giải pháp của BrenBarn (và tôi nghĩ dễ đọc hơn)
{k: v for k, v in metadata.items() if v}
Đã thử nghiệm với Python 2.7.3.
... if v!=None
như vậy: {k: v for k, v in metadata.items() if v!=None}
Nếu bạn thực sự cần sửa đổi từ điển gốc:
empty_keys = [k for k,v in metadata.iteritems() if not v]
for k in empty_keys:
del metadata[k]
Lưu ý rằng chúng tôi phải tạo danh sách các khóa trống vì chúng tôi không thể sửa đổi từ điển trong khi lặp qua nó (như bạn có thể nhận thấy). Tuy nhiên, điều này ít tốn kém hơn (khôn ngoan về bộ nhớ) so với việc tạo một từ điển hoàn toàn mới, trừ khi có rất nhiều mục nhập có giá trị trống.
.iteritems()
bằng .items()
, đầu tiên không hoạt động nữa trong các phiên bản Python mới nhất.
Giải pháp của BrenBarn là lý tưởng (và pythonic, tôi có thể thêm vào). Tuy nhiên, đây là một giải pháp (fp) khác:
from operator import itemgetter
dict(filter(itemgetter(1), metadata.items()))
Nếu bạn muốn có một cách tiếp cận đầy đủ tính năng nhưng ngắn gọn để xử lý các cấu trúc dữ liệu trong thế giới thực thường được lồng vào nhau và thậm chí có thể chứa các chu trình, tôi khuyên bạn nên xem tiện ích remap từ gói tiện ích boltons .
Sau khi pip install boltons
hoặc sao chép iterutils.py vào dự án của bạn, chỉ cần thực hiện:
from boltons.iterutils import remap
drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)
Trang này có nhiều ví dụ khác, bao gồm những ví dụ làm việc với các đối tượng lớn hơn nhiều từ API của Github.
Đó là Python thuần túy, vì vậy nó hoạt động ở mọi nơi và được thử nghiệm hoàn toàn bằng Python 2.7 và 3.3+. Hơn hết, tôi đã viết nó cho chính xác những trường hợp như thế này, vì vậy nếu bạn tìm thấy một trường hợp nó không xử lý được, bạn có thể sửa lỗi cho tôi ngay tại đây .
Dựa trên giải pháp của Ryan , nếu bạn cũng có danh sách và từ điển lồng nhau:
Đối với 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
Đối với 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": "" }] }
Nếu bạn có một từ điển lồng nhau và bạn muốn điều này hoạt động ngay cả đối với các phần tử con trống, bạn có thể sử dụng một biến thể đệ quy của đề xuất của 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()
thay vì iteritems()
cho 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'
}
'''
Đối với python 3
dict((k, v) for k, v in metadata.items() if v)
Dựa trên các câu trả lời từ Patriciasz và nneonneo , đồng thời tính đến khả năng bạn có thể muốn xóa các khóa chỉ có một số thứ giả mạo nhất định (ví dụ ''
) chứ không phải những thứ khác (ví dụ 0
), hoặc có thể bạn thậm chí muốn bao gồm một số thứ trung thực (ví dụ 'SPAM'
) , sau đó bạn có thể tạo một danh sách hit cụ thể:
unwanted = ['', u'', None, False, [], 'SPAM']
Thật không may, điều này không hoàn toàn hoạt động, vì ví dụ như 0 in unwanted
đánh giá True
. Chúng ta cần phân biệt giữa 0
những thứ giả dối và những thứ giả tạo khác, vì vậy chúng ta phải sử dụng is
:
any([0 is i for i in unwanted])
... đánh giá đến False
.
Bây giờ hãy sử dụng nó vào del
những việc không mong muốn:
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]
Nếu bạn muốn có một từ điển mới, thay vì sửa đổi metadata
tại chỗ:
newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])}
[]
Tôi đã đọc tất cả các câu trả lời trong chủ đề này và một số cũng được đề cập đến chủ đề này: Loại bỏ các ô trống trong từ điển lồng nhau bằng hàm đệ quy
Tôi ban đầu đã sử dụng giải pháp ở đây và nó hoạt động tuyệt vời:
Nỗ lực 1: Quá nóng (không hiệu quả hoặc sẽ có trong tương lai) :
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
Nhưng một số lo ngại về hiệu suất và khả năng tương thích đã được nêu ra trong thế giới Python 2.7:
isinstance
thay vìtype
for
vòng lặp để có hiệu quảitems
thay vìiteritems
Nỗ lực 2: Quá lạnh (Thiếu ghi nhớ) :
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! Đây không phải là đệ quy và hoàn toàn không phải là công cụ ghi nhớ.
Nỗ lực 3: Vừa phải (cho đến nay) :
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):
, sẽ xóa danh sách bằng cách sử dụng scrub_dict(d)
triển khai ban đầu . @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
Một cách thay thế bạn có thể làm điều này, là sử dụng từ điển hiểu. Điều này phải tương thích với2.7+
result = {
key: value for key, value in
{"foo": "bar", "lorem": None}.items()
if value
}
Đây là một tùy chọn nếu bạn đang sử dụng 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_)
Một số phương thức được đề cập ở trên bỏ qua nếu có bất kỳ số nguyên nào và thả nổi với các giá trị 0 & 0.0
Nếu ai đó muốn tránh những điều trên có thể sử dụng mã bên dưới (loại bỏ các chuỗi trống và giá trị Không có từ từ điển lồng nhau và danh sách lồng nhau):
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
"Vì tôi hiện cũng đang viết một ứng dụng dành cho máy tính để bàn cho công việc của mình với Python, tôi thấy trong ứng dụng nhập dữ liệu có rất nhiều mục nhập và một số mục không bắt buộc nên người dùng có thể để trống, vì mục đích xác thực, rất dễ lấy tất cả các mục nhập và sau đó loại bỏ khóa hoặc giá trị trống của từ điển. Vì vậy, đoạn mã của tôi ở trên cho thấy cách chúng tôi có thể dễ dàng lấy chúng ra, sử dụng tính năng hiểu từ điển và giữ phần tử giá trị từ điển không trống. Tôi sử dụng 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
vì vậy vòng lặp và xóa nhanh nhất là 160ns, đọc danh sách chậm hơn một nửa ở ~ 375ns và với cuộc gọi đến dict()
chậm hơn một nửa ~ 680ns.
Việc kết hợp 3 thành một hàm sẽ đưa nó trở lại khoảng 275ns. Ngoài ra, đối với tôi, PyPy nhanh gấp đôi so với trăn neet.
list(dic.items())
trong py 3. Đọc hiểu chính tả ftw sau đó? del vẫn có vẻ nhanh hơn đối với tỷ lệ giá trị Null / rỗng thấp. Tôi đoán việc xây dựng danh sách đó cũng không tốt cho việc tiêu thụ bộ nhớ hơn là chỉ tạo lại các câu lệnh.