Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python store dictionary path and read back in

I'm looping over a heavily nested dictionary of lists (system information) and storing the complete path to keys in this format:

.children[0].children[9].children[0].children[0].handle = PCI:0000:01:00.0
.children[0].children[9].children[0].children[0].description = Non-Volatile memory controller
.children[0].children[9].children[0].children[0].product = Samsung Electronics Co Ltd
.children[0].children[9].product = Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2
.children[2].product = PWS-406P-1R

Next, the complete paths are read in and will be compared to the system information (Data). How can I convert the complete path to this format?

Data['children'][0]['children'][9]['children'][0]['children'][0]['handle']
Data['children'][0]['children'][9]['product]'
Data['children'][2]['product']

I can do something like:

data = re.findall(r"\.([a-z]+)\[(\d+)\]", key, re.IGNORECASE)

[('children', '0'), ('children', '9'), ('children', '0'), ('children', '0')]
[('children', '0'), ('children', '9'), ('children', '0'), ('children', '0')]
[('children', '0'), ('children', '9'), ('children', '0'), ('children', '0')]
[('children', '0'), ('children', '9')]
[('children', '2')]

How can I convert one of these lists of tuples to be able to do:

if Data['children'][2]['product'] == expected:
    print('pass')
like image 409
officespacejam Avatar asked Nov 08 '22 08:11

officespacejam


1 Answers

You could use itertools, functools, and the operator libraries to chain the indexes together and recursively look them up to get the end value.

First, I think you should change the regex to pick up the last getter (i.e. handle, description, product)

re.findall(r"\.([a-z]+)(?:\[(\d+)\])?", key, re.IGNORECASE)

That should give you this

[('children', '0'), ('children', '9'), ('product', '')]

Then you can do something like this to chain the lookups

import operator
import functools
import itertools

indexes = [('children', '0'), ('children', '9'), ('product', '')]

# This turns the list above into a flat list ['children', 0, 'children', ...]
# It also converts number strings to integers and excludes empty strings.
keys = (int(k) if k.isdigit() else k for k in itertools.chain(*indexes) if k)

# functools.reduce recursively looks up the keys
# operator.getitem() is a functional version of Data[key] == getitem(Data, key)
value = functools.reduce(operator.getitem, keys, Data)
if value == expected:
    pass
like image 101
Brendan Abel Avatar answered Nov 14 '22 22:11

Brendan Abel