user2251503
user2251503

Reputation: 197

Python : Check specific key in nested dictionary and return all previous keys if its matched

I have a nested dictionary and i want to iterated whole dictionary to check for specific key. If its matched I want to return all keys which I iterated over to reach that specific key.

My Dictionary:

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

Excpected output:

aaa--description
aaa--ccc--description
xxx--description
xxx--bbb--ccc--ddd--description

I tried the below code but am not getting expected output

tmp_str = ""
def iter_dict(d):
    global tmp_str
    for key in sorted(d.keys()):
        if type(d[key]) == dict and len(d[key]) > 0:
            tmp_str += "--%s" %key
            iter_dict(d[key])
        elif key == "description":
            tmp_str += "--%s\n" %(key)

for key in d.keys():
    tmp_str += "\n\n%s" %key
    iter_dict(d[key])
print tmp_str

Please share your ideas.. thanks

Upvotes: 0

Views: 550

Answers (2)

Thierry Lathuille
Thierry Lathuille

Reputation: 24232

One way to do it with a recursive generator:

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


def paths_to_key(key, d, current_path=None):
    if current_path is None:
        current_path = []

    for k, v in d.items():
        if k == key:
            yield current_path + [key]
        else:
            if isinstance(v, dict):
                path = current_path + [k]
                yield from paths_to_key(key, v, path)

for path in paths_to_key('description', d):
    print(path)

Output:

['xxx', 'description']
['xxx', 'bbb', 'ccc', 'ddd', 'description']
['aaa', 'ccc', 'description']
['aaa', 'description']

Upvotes: 1

Bakuriu
Bakuriu

Reputation: 101929

You need to keep track of the keys you have seen when recursing. Just add a parameter to your iter_dict function and push/pop the keys there.

Also: do not use this global tmp_str, just return the value.

def iter_dict(d, rec_keys=None):
    rec_keys = rec_keys or []
    results = []
    for key, value in sorted(d.items(), key=lambda x: x[0]):
        if isinstance(value, dict) and value:
            results.append(iter_dict(value, rec_keys + [key]))
        elif key == "description":
            results.append('--'.join(rec_keys + ['description']))
    return '\n'.join(results)

tmp_str = iter_dict(d)

This results in:

>>> print(tmp_str)
aaa--ccc--description
aaa--description
xxx--bbb--ccc--ddd--description
xxx--description

I'll leave the ordering of the lines to you as an exercise.

Upvotes: 1

Related Questions