0

So I have a nested dictionary of arbitrary depth that is similar to this:

sample_dict = {
    'root_node': {
        'child_1': {
            'child_1a': {
                'child_1a_a': {},
                'child_1a_b': {},
                ...,
                'child_1a_x': {}
            },
            'child_1b': {
                'child_1b_a': {
                    'child_1b_a_a': {},
                    'child_1b_a_b': {},
                    ...
                },
                'child_1b_b': {
                    'child_1b_b_a': {},
                    ...
                },
                'child_1b_c': {}
            }
        },
        'child_2': {
                ...
            }
        }
    }

I need to convert the above dictionary into something like this:

sample_dict_output = {
    'title':'root_node',
    'key':'root_node',
    'children':[
        { 'title':'child_1',
          'key':'child_1',
          'children':[
              {'title':'child_1a',
               'key':'child_1a',
               'children':[
                 {'title': 'child_1a_a',
                  'key': 'child_1a_a'},
                 {'title': 'child_1a_b',
                  'key': 'child_1a_b'},
                   ...
                 {'title': 'child_1a_x',
                  'key': 'child_1a_x'},
               ],},
              {'title':'child_1b',
               'key':'child_1b',
               'children':[
                 {'title': 'child_1b_a',
                  'key': 'child_1b_a',
                  'children':[
                      {'title': 'child_1b_a_a',
                       'key': 'child_1b_a_a'},
                      {'title': 'child_1b_a_b',
                       'key': 'child_1b_a_b'},
                      ...
                  ],},
                 {'title': 'child_1b_b',
                  'key': 'child_1b_b',
                   'children':[
                    {'title': 'child_1b_b_a',
                     'key': 'child_1b_b_a'},
                    ...,
                 ],},
                {'title': 'child_1b_c',
                 'key': 'child_1b_c'}
                ],
              },
        { 'title':'child_2',
          'key':'child_2',
          'children':[...]
        }
    ],
}

I tried to search Stackoverflow for a solution and also attempted recursion, but to no avail. Hence, any help would be appreciated (preferably in Python 3.x). Thank you!

nb123
  • 72
  • 8
  • You should navigate into the dictionary, but that's not necessarily recursive. – Bora Jan 04 '21 at 13:29
  • Could you even begin to describe in English what the relationship between the output and the input is? *"... convert into something like this."* Really? – Booboo Jan 04 '21 at 13:30
  • What if the outer most dict is not a singleton? Shouldn't the whole ouptut be a list? – user2390182 Jan 04 '21 at 13:50

1 Answers1

1

The following will get you in the right direction:

def convert_item(key, val):
    conv = {
        "title": key, 
        "key": key, 
    }
    if val:
        conv["children"] = convert_dict(val)
    return conv

def convert_dict(dct):
    return [
        convert_item(k, v) for k, v in dct.items()
    ]

>>> convert_dict(sample_dict)[0]
{
    "title": "root_node",
    "key": "root_node",
    "children": [
        {
            "title": "child_1",
            "key": "child_1",
            "children": [
                {
                    "title": "child_1a",
                    "key": "child_1a",
                    "children": [
                        {"title": "child_1a_a", "key": "child_1a_a"},
                        {"title": "child_1a_b", "key": "child_1a_b"},
                        {"title": "child_1a_x", "key": "child_1a_x"},
                    ],
                },
                {
                    "title": "child_1b",
                    "key": "child_1b",
                    "children": [
                        {
                            "title": "child_1b_a",
                            "key": "child_1b_a",
                            "children": [
                                {"title": "child_1b_a_a", "key": "child_1b_a_a"},
                                {"title": "child_1b_a_b", "key": "child_1b_a_b"},
                            ],
                        },
                        {
                            "title": "child_1b_b",
                            "key": "child_1b_b",
                            "children": [
                                {"title": "child_1b_b_a", "key": "child_1b_b_a"}
                            ],
                        },
                        {"title": "child_1b_c", "key": "child_1b_c"},
                    ],
                },
            ],
        }
    ],
}

Or with a single recursive function:

def convert_dict(dct):
    return [
        {"title": k, "key": k, **({"children": convert_dict(v)} if v else {})}
        for k, v in dct.items()
    ]
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • Nope, not really. This is just for convenience and readability, you could easily transform this to a single function. – user2390182 Jan 04 '21 at 14:05
  • The only issues that can arise are if your data deviates from the given structure or contains a circle (any dict in there containing itself as a (nested) value). But that would make any naive implementation recurse infinitely. – user2390182 Jan 04 '21 at 14:11
  • `**` unpacks the dictionary it is applied to. This is a trick to flatten in the potentially empty dict containing the "children" key. – user2390182 Jan 04 '21 at 14:41
  • This does exactly the same as the two-function variant. Inserts the children key only if there are children (a non-empty val). – user2390182 Jan 04 '21 at 14:42