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