How to clean a nested python dict from keys with empty strings and Nones BUT NOT 0 or false

Question:

I have two issues:

  1. 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.

  2. 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?

Asked By: PloniStacker

||

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}}
Answered By: mozway
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.