Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

list of tuples to dictionary of dictionaries [closed]

I am retrieving (root, parent1, parent2, child1), from a hierarchical database in form of list of tuples as:

[('HCS', 'Assured Build', 'Implementation', 'Hardware Stack'), 
('HCS', 'Assured Build', 'Implementation', 'SA and SF'),
('HCS', 'Assured Build', 'Testing and Validation', 'NFRU-SS'),
('HCS', 'Assured Build', 'Testing and Validation', 'NRFU-UC'), 
('HCS', 'Assured Platform', 'Restoration', 'AS Build'), 
('HCS', 'Assured Platform', 'Restoration', 'Capacity Management'),
('HCS', 'Assured Platform', 'Migration', 'Document Review')]

I want to create a dictionary of dictionary like to iterate easily and create a tree view:

{"HCS":
      {"Assured Build":
             {"Implementation":{"Hardware Stack", "Software"},
             {"Testing and Validation":{"NRFU-SS", "NRFU-UC"}
      },
      {"Assured Platform":
              {"Restoration":{"AS Build","Capacity Management"},
              {"Migration":{"Document Review"}},
      }

}

What is the best way to handle this? I have tried namedtuple and defaultdict with failure.

like image 482
MalTec Avatar asked Feb 06 '23 23:02

MalTec


1 Answers

You need the defaultdict of defaultdict of defaultdict of a list (or set if needed):

import json
from collections import defaultdict

l = [('HCS', 'Assured Build', 'Implementation', 'Hardware Stack'),
     ('HCS', 'Assured Build', 'Implementation', 'SA and SF'),
     ('HCS', 'Assured Build', 'Testing and Validation', 'NFRU-SS'),
     ('HCS', 'Assured Build', 'Testing and Validation', 'NRFU-UC'),
     ('HCS', 'Assured Platform', 'Restoration', 'AS Build'),
     ('HCS', 'Assured Platform', 'Restoration', 'Capacity Management'),
     ('HCS', 'Assured Platform', 'Migration', 'Document Review')]

d = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
for key1, key2, key3, value in l:
    d[key1][key2][key3].append(value)

print(json.dumps(d, indent=4))

json.dumps() here is just for a pretty print. It prints:

{
    "HCS": {
        "Assured Platform": {
            "Restoration": [
                "AS Build",
                "Capacity Management"
            ],
            "Migration": [
                "Document Review"
            ]
        },
        "Assured Build": {
            "Implementation": [
                "Hardware Stack",
                "SA and SF"
            ],
            "Testing and Validation": [
                "NFRU-SS",
                "NRFU-UC"
            ]
        }
    }
}

We can also make the nested defauldict initialization step a bit more generic and extract that into a reusable method:

def make_defaultdict(depth, data_structure):
    d = defaultdict(data_structure)
    for _ in range(depth):
        d = defaultdict(lambda d=d: d)
    return d

Then, you can replace:

d = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))

with:

d = make_defaultdict(2, list)
like image 54
alecxe Avatar answered Feb 22 '23 01:02

alecxe