xeor
xeor

Reputation: 5455

Getting a python dict.keys trail for each item

I have a python dict that looks like this

{'data': [{'data': [{'data': 'gen1', 'name': 'objectID'},
                   {'data': 'familyX', 'name': 'family'}],
          'name': 'An-instance-of-A'},
         {'data': [{'data': 'gen2', 'name': 'objectID'},
                   {'data': 'familyY', 'name': 'family'},
                   {'data': [{'data': [{'data': '21',
                                        'name': 'objectID'},
                                       {'data': 'name-for-21',
                                        'name': 'name'},
                                       {'data': 'no-name', 'name': None}],
                              'name': 'An-instance-of-X:'},
                             {'data': [{'data': '22',
                                        'name': 'objectID'}],
                              'name': 'An-instance-of-X:'}],
                    'name': 'List-of-2-X-elements:'}],
          'name': 'An-instance-of-A'}],
'name': 'main'}

The structure is repeating and its rule is like:

The problem is that for each value, I need to know every info for each parent.

So at the end, I need to print a list with items that looks something like:

objectID=gen2 family=familyY An-instance-of-X_objectID=21 An-instance-of-X_name=name-for-21

Edit: This is only one of several lines I want as the output. I need one line like this for each item that doesn’t have a dict as 'data'.

So, for each data that is not a dict, traverse up, find info and print it..

I don't know every function in modules like itertools and collections. But is there something in there I can use? What is this called (when I am trying to do research on my own)?

I can find many "flatten dict" methods, but not like this, not when I have 'data', 'name' like this..

Upvotes: 2

Views: 127

Answers (1)

Thorsten Kranz
Thorsten Kranz

Reputation: 12765

This is a wonderful example what recursion is good for:

input_ = {'data': [{'data': [{'data': 'gen1', 'name': 'objectID'},
                   {'data': 'familyX', 'name': 'family'}],
          'name': 'An-instance-of-A'},
         {'data': [{'data': 'gen2', 'name': 'objectID'},
                   {'data': 'familyY', 'name': 'family'},
                   {'data': [{'data': [{'data': '21',
                                        'name': 'objectID'},
                                       {'data': 'name-for-21',
                                        'name': 'name'},
                                       {'data': 'no-name', 'name': None}],
                              'name': 'An-instance-of-X:'},
                             {'data': [{'data': '22',
                                        'name': 'objectID'}],
                              'name': 'An-instance-of-X:'}],
                    'name': 'List-of-2-X-elements:'}],
          'name': 'An-instance-of-A'}],
'name': 'main'}

def parse_dict(d, predecessors, output):
    """Recurse into dict and fill list of path-value-pairs"""
    data = d["data"]
    name = d["name"]
    name = name.strip(":") if type(name) is str else name
    if type(data) is list:
        for d_ in data:
            parse_dict(d_, predecessors + [name], output)
    else:
        output.append(("_".join(map(str,predecessors+[name])), data))

result = []

parse_dict(input_, [], result)

print "\n".join(map(lambda x: "%s=%s"%(x[0],x[1]),result))

Output:

main_An-instance-of-A_objectID=gen1
main_An-instance-of-A_family=familyX
main_An-instance-of-A_objectID=gen2
main_An-instance-of-A_family=familyY
main_An-instance-of-A_List-of-2-X-elements_An-instance-of-X_objectID=21
main_An-instance-of-A_List-of-2-X-elements_An-instance-of-X_name=name-for-21
main_An-instance-of-A_List-of-2-X-elements_An-instance-of-X_None=no-name
main_An-instance-of-A_List-of-2-X-elements_An-instance-of-X_objectID=22

I hope I understood your requirements correctly. If you don't want to join the paths into strings, you can keep the list of predecessors instead.

Greetings,

Thorsten

Upvotes: 3

Related Questions