User
User

Reputation: 95

How to retrieve all 'groups' from a nested dictionary

From a given dictionary that looks as follows:

{
    'parent1': {
        'child1-1': {
            'element1': 'val1',
            'element2': 'val2'
        },
        'child1-2': {
            'element1': 'val1',
            'element2': 'val2'
        }
    },
    'parent2': {
        'child2-1': {
            'subchild2-1-1': {
              'subelement1': 'val1'  
            },
            'element2': 'val2'
        },
        'child2-2': {
            'element1': 'val1',
            'element2': 'val2'
        }
    }
}

I would like to retrieve all keys for the nested groups as follows:

'parent1':       ['child1-1', 'child1-2']
'child1-1':      ['element1', 'element2']
'child1-2':      ['element1', 'element2']
'parent2':       ['child2-1', 'child2-2']
'child2-1':      ['subchild2-1-1', 'element2']
'subchild2-1-1': ['subelement1']
'child2-2':      ['element1', 'element2']

Output may be in a new dictionary, ordering of the output is not important and all leaf elements should be ignored. The amount of nested levels should be arbitrary as nesting could potentially go on 'infinitely'.

This is my current code:

def dict_depth(d):
    if isinstance(d, dict):
        return 1 + (max(map(dict_depth, d.values())) if d else 0)
    return 0

group_dict = {}
def retrieve_groups(d):
    for k, v in d.items():
        if isinstance(v, dict) and dict_depth(v) != 1:
            retrieve_groups(v)
            group_dict[k] = list(v.keys())

retrieve_groups(c)
print(group_dict)

Which returns the following:

{'child2-1': ['subchild2-1-1', 'element2'],
 'parent1': ['child1-1', 'child1-2'],
 'parent2': ['child2-1', 'child2-2']}

This clearly isn't complete as subgroups are missing. I feel like I'm overcomplicating this...

Upvotes: 0

Views: 34

Answers (1)

hiro protagonist
hiro protagonist

Reputation: 46899

this does what you want:

def retrieve_groups(d, ret={}):
    ret.update({key: [subkey for subkey in value] 
                for key, value in d.items() if isinstance(value, dict)})
    for value in d.values():
        if not isinstance(value, dict):
            continue
        retrieve_groups(d=value, ret=ret)

    return ret

where i use ret as mutable argument that is updated during the recursion. the rest should be straight-forward.

the output is:

{   'child1-1': ['element1', 'element2'],
    'child1-2': ['element1', 'element2'],
    'child2-1': ['subchild2-1-1', 'element2'],
    'child2-2': ['element1', 'element2'],
    'parent1': ['child1-1', 'child1-2'],
    'parent2': ['child2-1', 'child2-2'],
    'subchild2-1-1': ['subelement1']}

Upvotes: 1

Related Questions