Wizix Wizix - 5 months ago 13
Python Question

Get values from a nested dictionary to a list

It's very strange that nobody asks this before. I can't find any answer for this on internet. I have a nested dictionnary and I want a list of all it values (not nested list). This is my code :

dico = {
"Balance": {
"Normal": {
"P1x": 0.889,
"P1y": 700.0,
"P2x": 0.889,
"P2y": 884.0,
"P3x": 1.028,
"P3y": 1157.0,
"P4x": 1.201,
"P4y": 1157.0,
"P5x": 1.201,
"P5y": 700.0
},
"Utility": {
"P1x": 0.889,
"P1y": 700.0,
"P2x": 0.889,
"P2y": 884.0,
"P3x": 0.947,
"P3y": 998.0,
"P4x": 1.028,
"P4y": 998.0,
"P5x": 1.028,
"P5y": 700.0,
}
}
}

def grab_children(father):
local_list = []
for key, value in father.items():
local_list.append(value)
local_list.extend(grab_children(father[key]))
return local_list

print(grab_children(dico))


The dictionnary is normaly much longer and contain strings, booleans, integers and floats.

When I try my function, it said
AttributeError: 'str' object has no attribute 'items'


I understand why, but I don't see how to fix it... Can you help me ?

Thanks!

Answer

You can try:

import collections

def walk(node):
    for key, item in node.items():
        if isinstance(item, collections.Mapping):
            print(key)
            walk(item)
        else:
            print('\t',key, item)

With your example, prints:

Balance
Utility
     P3y 998.0
     P1x 0.889
     P5x 1.028
     P5y 700.0
     P2x 0.889
     P1y 700.0
     P2y 884.0
     P4x 1.028
     P3x 0.947
     P4y 998.0
Normal
     P3y 1157.0
     P1x 0.889
     P5x 1.201
     P5y 700.0
     P2x 0.889
     P1y 700.0
     P2y 884.0
     P4x 1.201
     P3x 1.028
     P4y 1157.0

Under Python 3.3+, you can do:

def walk(node):
    for key, value in node.items():
        if isinstance(value, collections.Mapping):
            yield from walk(value)
        else:
            yield key, value 

>>> list(walk(dico))
[('P5y', 700.0), ('P2y', 884.0), ('P4y', 1157.0), ('P4x', 1.201), ('P1x', 0.889), ('P3y', 1157.0), ('P2x', 0.889), ('P1y', 700.0), ('P3x', 1.028), ('P5x', 1.201), ('P5y', 700.0), ('P2y', 884.0), ('P4y', 998.0), ('P4x', 1.028), ('P1x', 0.889), ('P3y', 998.0), ('P2x', 0.889), ('P1y', 700.0), ('P3x', 0.947), ('P5x', 1.028)]

Then if you ONLY want the values:

def walk(node):
    for key, value in node.items():
        if isinstance(value, collections.Mapping):
            yield from walk(value)
        else:
            yield value    

>>> list(walk(dico))
[700.0, 0.889, 0.889, 998.0, 1.028, 0.947, 700.0, 884.0, 998.0, 1.028, 700.0, 0.889, 0.889, 1157.0, 1.201, 1.028, 700.0, 884.0, 1157.0, 1.201]

Bear in mind, however, that Python dicts have no order so the order in the list of values has the same meaningless order as the dict that you feed it.

Comments