1

So I have an extract from a flat dictionary as shown:

dict= {"active_screen":"artboard_1","artboard_1.content1.grd_x":0,"artboard_2.content2.content3.grd_y":0,"artboard_2.content2.content3.grd_x":0}

I would like to make it hierarchical, like so:

{
    'active_screen': 'artboard_1',
    'artboard_1': {
            'content1':    {
                    'grd_x': 0
                           }
                  }
    'artboard_2': {
            'content2': {
                        'content3' : {
                            'grd_y': 0,
                            'grd_x': 0
                                   }
                        }
                  }
}

As you can see, each entry has different structures. I thought that this would be done using recursion, and attempted the following:

import collections
import re

def recursive_dict(collections_default_dict,a,value):
    collections_default_dict[a] = value
    return collections_default_dict
    
string = {"active_screen":"artboard_1","artboard_1.content1.grd_x":0,"artboard_2.content2.content3.grd_y":0,"artboard_2.content2.content3.grd_x":0}
e = collections.defaultdict(dict)
for key,value in string.items():
    counter=0
    matches = re.findall(r"([^.]*)",key)
    matches = filter(None, matches)
    for a in matches:
        recursive_dict(e,a,value)

But this didn't work. Can anyone help me? I need a loop instead of doing it manually since the above is just an extract of a bigger sample.

aldo
  • 89
  • 6

2 Answers2

0

This can be done in the following way:

import collections
import re

def recursive_dict(collections_default_dict,matches,value):
    if len(matches) == 1:
        collections_default_dict[matches[0]] = value
        return
    
    recursive_dict(collections_default_dict[matches[0]],
            matches[1:], value)
 

def make_dict():
    return collections.defaultdict(make_dict)

            
string = {"active_screen":"artboard_1","artboard_1.content1.grd_x":0,"artboard_2.content2.content3.grd_y":0,"artboard_2.content2.content3.grd_x":0}
e = make_dict()
for key,value in string.items():
    counter=0
    matches = re.findall(r"([^.]*)",key)
    matches = list(filter(None, matches))
    recursive_dict(e,matches,value)
Michael Butscher
  • 10,028
  • 4
  • 24
  • 25
0

This is achievable with very little python. I've not made use of the default dict, but I think this is simple enough not to need it:

def make_recursive_entry(output_dict, address, value):
  if len(address) == 1:
    output_dict[address[0]] = value
  else:
    inner_dict = output_dict.get(address[0], {})
    output_dict[address[0]] = inner_dict
    make_recursive_entry(inner_dict, address[1:], value)


input_dict = {"active_screen":"artboard_1","artboard_1.content1.grd_x":0,"artboard_2.content2.content3.grd_y":0,"artboard_2.content2.content3.grd_x":0}


output_dict = {}
for key, value in input_dict.items():
  address = key.split('.')
  make_recursive_entry(output_dict, address, value)


print(output_dict)

We split to lists of address items. We then pass an output dictionary into make recursive entry. In this function, if the address has one item, we can assume we are at a leaf node, and insert the value. Otherwise, we ensure that there is a dictionary with this name, and recurse in with 1 fewer address item to make the inner entries.

Danny Staple
  • 7,101
  • 4
  • 43
  • 56
  • Hi Danny, thank you it works very well! I have an unrelated question if you don't mind; how did you get this good at Python algorithms? Where did you learn such things to solve this kind of problem? I also have a lot of problems similar to this but I can't solve it; are these problems addressed in algorithm and data structure classes? – aldo May 05 '21 at 07:16
  • hmm - I've been programming for decades, with at more than 10 years of python. I do have an applied computing (not comp sci) degree, but much of this is a lot of practice. Brilliant.org is good for algo stuff, and exercism.io good for getting to know python with practice. Do a bit of coding every day - any language and it will help. – Danny Staple May 06 '21 at 09:53