Reputation: 3136
What is the proper way to remove keys from a dictionary with value == None
in Python?
Upvotes: 127
Views: 132427
Reputation: 11746
Here is a recursive function returning a new clean dictionary without keys with None
values:
def clean_dict(d):
clean = {}
for key, value in d.items():
if value is not None:
if isinstance(value, dict):
subdict = clean_dict(value)
if subdict:
clean[key] = subdict
else:
clean[key] = value
return clean
example = {
"a": 12, "b": "", "c": None, "d": {"e": {"f": None}},
"k": {"d": 34, "t": None, "m": {"k": [], "t": {"x": 0}}, None: 123}
}
print(clean_dict(example))
Output is
{'a': 12, 'b': '', 'k': {'d': 34, 'm': {'k': [], 't': {'x': 0}}, None: 123}}
Note that it also removed "d": {"e": {"f": None}}
from the result.
Upvotes: 0
Reputation: 3543
if you need to delete None values recursively, better to use this one:
def delete_none(_dict):
"""Delete None values recursively from all of the dictionaries"""
for key, value in list(_dict.items()):
if isinstance(value, dict):
delete_none(value)
elif value is None:
del _dict[key]
elif isinstance(value, list):
for v_i in value:
if isinstance(v_i, dict):
delete_none(v_i)
return _dict
with advice of @dave-cz, there was added functionality to support values in list type.
@mandragor added additional if statement to allow dictionaries which contain simple lists.
Here's also solution if you need to remove all of the None values from dictionaries, lists, tuple, sets:
def delete_none(_dict):
"""Delete None values recursively from all of the dictionaries, tuples, lists, sets"""
if isinstance(_dict, dict):
for key, value in list(_dict.items()):
if isinstance(value, (list, dict, tuple, set)):
_dict[key] = delete_none(value)
elif value is None or key is None:
del _dict[key]
elif isinstance(_dict, (list, set, tuple)):
_dict = type(_dict)(delete_none(item) for item in _dict if item is not None)
return _dict
The result is:
# passed:
a = {
"a": 12, "b": 34, "c": None,
"k": {"d": 34, "t": None, "m": [{"k": 23, "t": None},[None, 1, 2, 3],{1, 2, None}], None: 123}
}
# returned:
a = {
"a": 12, "b": 34,
"k": {"d": 34, "m": [{"k": 23}, [1, 2, 3], {1, 2}]}
}
Upvotes: 21
Reputation: 131
Python3 recursive version
def drop_nones_inplace(d: dict) -> dict:
"""Recursively drop Nones in dict d in-place and return original dict"""
dd = drop_nones(d)
d.clear()
d.update(dd)
return d
def drop_nones(d: dict) -> dict:
"""Recursively drop Nones in dict d and return a new dict"""
dd = {}
for k, v in d.items():
if isinstance(v, dict):
dd[k] = drop_nones(v)
elif isinstance(v, (list, set, tuple)):
# note: Nones in lists are not dropped
# simply add "if vv is not None" at the end if required
dd[k] = type(v)(drop_nones(vv) if isinstance(vv, dict) else vv
for vv in v)
elif v is not None:
dd[k] = v
return dd
Upvotes: 2
Reputation: 446
Maybe you'll find it useful:
def clear_dict(d):
if d is None:
return None
elif isinstance(d, list):
return list(filter(lambda x: x is not None, map(clear_dict, d)))
elif not isinstance(d, dict):
return d
else:
r = dict(
filter(lambda x: x[1] is not None,
map(lambda x: (x[0], clear_dict(x[1])),
d.items())))
if not bool(r):
return None
return r
it would:
clear_dict(
{'a': 'b', 'c': {'d': [{'e': None}, {'f': 'g', 'h': None}]}}
)
->
{'a': 'b', 'c': {'d': [{'f': 'g'}]}}
Upvotes: -1
Reputation: 97
if you don't want to make a copy
for k,v in list(foo.items()):
if v is None:
del foo[k]
Upvotes: 5
Reputation: 1981
For python 2.x
:
dict((k, v) for k, v in original.items() if v is not None)
Upvotes: 4
Reputation: 309821
Generally, you'll create a new dict
constructed from filtering the old one. dictionary comprehensions are great for this sort of thing:
{k: v for k, v in original.items() if v is not None}
If you must update the original dict, you can do it like this ...
filtered = {k: v for k, v in original.items() if v is not None}
original.clear()
original.update(filtered)
This is probably the most "clean" way to remove them in-place that I can think of (it isn't safe to modify a dict while you're iterating over it)
Use original.iteritems()
on python2.x
Upvotes: 211
Reputation: 21609
You could also take a copy of the dict
to avoid iterating the original dict
while altering it.
for k, v in dict(d).items():
if v is None:
del d[k]
But that might not be a great idea for larger dictionaries.
Upvotes: 3