How do I store in a tuple or list the values of a JSON dictionary in Python?

1

I currently have the following JSON dictionary:

tree =
{
    'MADRE': '323', 'reports':
        [{
            'MADRE': '4444', 'reports':
                [{'MADRE': '5'}, {'MADRE': '4'}]
        }, {'MADRE': '3',
            'reports': [{'MADRE': '33'}, {'MADRE': '6'}, {
                'MADRE': '99',
                'reports': [{'MADRE': '233'}]
            }, {'MADRE': '7'}]
        }]
} 

What I want to get is something like this:

[(323,4444), (323,5), (323, 4), (323, 3), (323, 33), (323, 6), (323, 99), (323, 233), (323, 7)]

That is, obtain the first element and make it static so that it has tuples with each value of the dictionary.

In this way then generate an output to create a dataframe .

    
asked by Julio Alemán Méndez 24.09.2018 в 16:15
source

1 answer

0

As you put it, your problem is reduced in principle to get all the values of a certain key in the JSON ( dict ) through all the possible levels of nesting. A possible recursive implementation, which for this is quite simple, could be:

def find_key(target, obj):
    if isinstance(obj, dict):
        for key, value in obj.items():
            if key == target:
                yield value

            elif isinstance(value, dict):
                yield from find_key(target, value)

            elif isinstance(value, list):
                for item in value:
                    yield from find_key(target, item)

    elif isinstance(obj, list):
        for item in obj:
            yield from find_key(target, item)

It can be done iteratively using a queue, for example:

from collections import deque


def find_key(target, obj):
    queue = deque()
    queue.append(obj)
    while queue:
        obj = queue.pop()
        if isinstance(obj, dict):
            for key, value in obj.items():
                if key == target:
                    yield value
                elif isinstance(value, dict):
                    queue.append(value)
                elif isinstance(value, list):
                    queue.extend(reversed(value))
        elif isinstance(obj, list):
            queue.extend(reversed(value))

The function is a generator, as you want to keep the first value found as the first element of the tuples, you can do something like this:

tree = {
    'MADRE': 323, 'reports':
        [{
            'MADRE': 4444, 'reports':
                [{'MADRE': 5}, {'MADRE': 4}]
          },
         {'MADRE': 3,
            'reports': [{'MADRE': 33}, {'MADRE': 6}, {
                'MADRE': 99,
                'reports': [{'MADRE': 233}]
            }, {'MADRE': 7}]
        }]
} 

f_gen = find_key("MADRE", tree)
a = next(f_gen) # Primer valor para la clave
res = [(a, b) for b in f_gen]
>>> res
[(323, 4444), (323, 5), (323, 4),
 (323, 3), (323, 33), (323, 6),
 (323, 99), (323, 233), (323, 7)]

Edit

yield from that allows you to delegate to a subgenerator was introduced in Python 3.3, if used a previous version we must iterate directly on the generator with for in and use yield , leaving the recursive version something like this:

def find_key(target, obj):
    if isinstance(obj, dict):
        for key, value in obj.items():
            if key == target:
                yield value

            elif isinstance(value, dict):
                for item in find_key(target, value):
                    yield item

            elif isinstance(value, list):
                for item in value:
                    for r in find_key(target, item):
                        yield r

    elif isinstance(obj, list):
        for item in obj:
            for r in find_key(target, item):
                yield r
    
answered by 24.09.2018 / 19:50
source