How to clean a nested python dict from keys with empty strings and Nones BUT NOT 0 or false
Question:
I have two issues:
-
I created a function that cleans None keys from my dictionary but I couldn’t figure out how to clean recursively if i have dictionaries within my dictionary.
-
I was also able to remove None and empty strings with if value:
condition I ended up removing false and 0 values which is not what I am looking for. I am only looking to remove keys with None values or empty keys.
def clean_dict(dict_with_nones):
return {key: value for key, value in dict_with_nones.items() if value is not None}
This works well in cleaning Nones with a flat dictionary, I tried to add another condition to remove the empty strings:
def clean_dict(dict_with_nones):
return {key: value for key, value in dict_with_nones.items() if value is not None or value != ""}
Something about the way I constructed the condition here causes is the None detection not to work as well… I tried surrounding the condition with () but it didnt help.
So back to my question, How can I remove keys with empty values or None values from a nested dictionary?
Answers:
Assuming you really want to clean the keys, not values:
def clean_dict(dict_with_nones):
if not isinstance(dict_with_nones, dict):
return dict_with_nones
return {key: clean_dict(value) for key, value in dict_with_nones.items()
if key is not None}
test = {None: {'a': 1}, 'b': {'c': {None: 2}, 'd': 3, None: 4}}
out = clean_dict(test)
output:
{'b': {'c': {}, 'd': 3}}
variant to avoid yielding null values:
def clean_dict(dict_with_nones):
if not isinstance(dict_with_nones, dict):
return dict_with_nones
return {key: v
for key, value in dict_with_nones.items()
if key is not None and (v:=clean_dict(value))}
out = clean_dict(test)
output:
{'b': {'d': 3}}
removing VALUES
If you meant to remove falsy values (None, empty string, etc.)
def clean_dict_value(d):
if not isinstance(d, dict):
return d if d else False # use a custom test if needed
return {key: v
for key, value in d.items()
if (v:=clean_dict_value(value))}
test = {'a': {'b': 1}, 'c': {'d': None, 'e': 3, 'f': {'g': ''}}, 'h': None}
clean_dict_value(test)
output:
{'a': {'b': 1}, 'c': {'e': 3}}
removing only ''
, None
and empty dictionary:
NB. remove {}
from ('', None, {})
to keep empty dictionaries
def clean_dict_value(d):
if not isinstance(d, dict):
return d
return {key: v
for key, value in d.items()
if (v:=clean_dict_value(value)) not in ('', None, {})}
test = {'a': {'b': 1}, 'c': {'d': None, 'e': False, 'f': {'g': ''}}, 'h': None}
clean_dict_value(test)
output:
{'a': {'b': 1}, 'c': {'e': False}}
I have two issues:
-
I created a function that cleans None keys from my dictionary but I couldn’t figure out how to clean recursively if i have dictionaries within my dictionary.
-
I was also able to remove None and empty strings with
if value:
condition I ended up removing false and 0 values which is not what I am looking for. I am only looking to remove keys with None values or empty keys.def clean_dict(dict_with_nones):
return {key: value for key, value in dict_with_nones.items() if value is not None}
This works well in cleaning Nones with a flat dictionary, I tried to add another condition to remove the empty strings:
def clean_dict(dict_with_nones):
return {key: value for key, value in dict_with_nones.items() if value is not None or value != ""}
Something about the way I constructed the condition here causes is the None detection not to work as well… I tried surrounding the condition with () but it didnt help.
So back to my question, How can I remove keys with empty values or None values from a nested dictionary?
Assuming you really want to clean the keys, not values:
def clean_dict(dict_with_nones):
if not isinstance(dict_with_nones, dict):
return dict_with_nones
return {key: clean_dict(value) for key, value in dict_with_nones.items()
if key is not None}
test = {None: {'a': 1}, 'b': {'c': {None: 2}, 'd': 3, None: 4}}
out = clean_dict(test)
output:
{'b': {'c': {}, 'd': 3}}
variant to avoid yielding null values:
def clean_dict(dict_with_nones):
if not isinstance(dict_with_nones, dict):
return dict_with_nones
return {key: v
for key, value in dict_with_nones.items()
if key is not None and (v:=clean_dict(value))}
out = clean_dict(test)
output:
{'b': {'d': 3}}
removing VALUES
If you meant to remove falsy values (None, empty string, etc.)
def clean_dict_value(d):
if not isinstance(d, dict):
return d if d else False # use a custom test if needed
return {key: v
for key, value in d.items()
if (v:=clean_dict_value(value))}
test = {'a': {'b': 1}, 'c': {'d': None, 'e': 3, 'f': {'g': ''}}, 'h': None}
clean_dict_value(test)
output:
{'a': {'b': 1}, 'c': {'e': 3}}
removing only ''
, None
and empty dictionary:
NB. remove {}
from ('', None, {})
to keep empty dictionaries
def clean_dict_value(d):
if not isinstance(d, dict):
return d
return {key: v
for key, value in d.items()
if (v:=clean_dict_value(value)) not in ('', None, {})}
test = {'a': {'b': 1}, 'c': {'d': None, 'e': False, 'f': {'g': ''}}, 'h': None}
clean_dict_value(test)
output:
{'a': {'b': 1}, 'c': {'e': False}}