Check every layer of nested dict for two specific keys and return key value pair

Viewed 42

I have already tried numerous approaches, but unfortunately do not come to any useful result. I have the following problem: I have a very deep and arbitrary nested dictionary.

d = {
    "aaa":{
        "bbb":"xyz",
        "ccc":{
            "description":"xyz",
            "data":"abc"
        },
        "description":"xyz"
    },
    "xxx":{
        "description":"xyz",
        "bbb":{
            "ccc":{
                "ddd":{
                    "description":"xyz"
                },
                "aaa":{
                    "description":{
                        "hhh": "xyz"
                    }
                },
                "zzz":{
                    "description":"xyz"
                }
            }
        }
    },
    "lll":{
        "description":"xyz",
        "bbb":{
            "ccc":{
                "hhh":{
                    "description":"xyz"
                },
                "ooo":{
                    "description":"xyz",
                    "aaa":{
                        "ddd":{
                            "description":"xyz"
                        }
                    },
                    "zzz":{
                        "ddd":{
                            "description":"xyz"
                        }
                    }
                },
                "zzz":{
                    "description":"xyz"
                }
            }
        }
    }
} 

Now I want to search all levels of the dictionary and check if the keys "aaa" & "zzz" occur in this level. If this is the case, I want to output the keys with the respective values in a list with tuples.

[('aaa:  {'ddd':{'description':'xyz'}', 'zzz:  {'description':'xyz'}'),
('aaa:{'ddd':{'description':'xyz'}}', 'zzz:{'description':'xyz'})
]

I know that with

d.keys() 

can print all keys in one layer.

I know that with this function I can go through all keys and values in the dictionary

def recursive_items(dictionary):
    for key, value in dictionary.items():
        if type(value) is dict:
            yield from recursive_items(value)
        else:
            yield (key, value)

However, I am having trouble linking the two and putting the output into a list of tuples.

1 Answers

Try (d is dictionary from your question):

def find(d, keys=("aaa", "zzz")):
    if isinstance(d, dict):
        if all(k in d for k in keys):
            yield tuple((k, d[k]) for k in keys)
        for v in d.values():
            yield from find(v, keys)
    elif isinstance(d, list):
        for v in d:
            yield from find(v, keys)


print(list(find(d)))

Prints:

[
    (
        ("aaa", {"description": {"hhh": "xyz"}}), 
        ("zzz", {"description": "xyz"})),
    (
        ("aaa", {"ddd": {"description": "xyz"}}),
        ("zzz", {"ddd": {"description": "xyz"}}),
    ),
]

Related