S
As your problem arises, it is reduced in principle to obtaining all the values of a given key in JSON (JSON).dict) going all possible nesting levels. 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 by 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 maintain 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)]
Edition https://www.python.org/dev/peps/pep-0380/ which allows delegating to a sub-generator was introduced to Python 3.3, if a previous version is used we iterate directly over the generator with a for in and use yield, remaining 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