Get data from a nested dict python and data type is also mixed

Viewed 115

Json data is given below, I have to fetch the coords in the given data and print the list of it as:

Solution: [[2, 3], [4, 1], [8, 4], [3, 2]]

data = '{"foo": {"type": "geo", "coords": [2, 3], "children": [{"type": "geo", "coords": [4, 1], "children": [{"type": "bar", "children": [{"type": "geo", "coords": [8, 4]}]}, {"type": "geo", "coords": [3, 2]}]}]}}'

I have come up with a solution but that has indexing with it. I want some generic solution that works in every case of it, no matter what is the structure of dict. Is it possible? I yes then How?

My solution for this is:

def fun(data):
    coords_list = list()
    data = json.loads(data)
    for k in data:
        if data[k].get('coords') is not None:
            coords_list.append(data[k]['coords'])
        if data[k].get('children') is not None:
            if isinstance(data[k].get('children'), list):
                coords = data[k].get('children')[0].get('coords')
                coords_list.append(coords)
                if isinstance(data[k].get('children')[0].get('children'), list):
                    coords = data[k].get('children')[0].get('children')[0].get('children')[0].get('coords')
                    coords_list.append(coords)
                    coords = data[k].get('children')[0].get('children')[1].get('coords')
                    coords_list.append(coords)
    return coords_list
3 Answers

Converting the json to string makes it possible to apply regex.

import re
coords = []
for c in re.findall( r'\[([0-9]), ([0-9])*', str(data)):    
    coords.append([int(c[0]), int(c[1])])

coords:

[[2, 3], [4, 1], [8, 4], [3, 2]]

Explanation of regex \[([0-9]), ([0-9])*:

  • \[ match a [.
  • (...) create a group, used twice. Enables c[0] and c[1].
  • [0-9]+ match all characters between 0-9. Can be extended to include dots or comma's via [0-9.,].
  • , space between the two coords.
  • * do this multiple times. That's why we loop over the results.

You can use recursion to search for coords:

import json


def get_coords(d):
    if isinstance(d, dict):
        for k, v in d.items():
            if k == "coords":
                yield v
            yield from get_coords(v)
    if isinstance(d, list):
        for v in d:
            yield from get_coords(v)


data = '{"foo": {"type": "geo", "coords": [2, 3], "children": [{"type": "geo", "coords": [4, 1], "children": [{"type": "bar", "children": [{"type": "geo", "coords": [8, 4]}]}, {"type": "geo", "coords": [3, 2]}]}]}}'
data = json.loads(data)

out = list(get_coords(data))
print("Solution:", out)

Prints:

Solution: [[2, 3], [4, 1], [8, 4], [3, 2]]

One option could be recursion, saving the coords present in your data.

# 1. Convert json to dict
data = json.loads(data)['foo']
# 2. coords is set with the first coord: [2, 3]
coords = [data['coords']]

def get_solution(data):
  for dictionary in data:
    for key,value in dictionary.items():
      if key == 'coords':
        # Save the next coord
        coords.append(value)
      if key == 'children':
        # Send the next 'children'
        get_solution(value)
  return coords

solution = get_solution(data['children'])
print(solution)

Output:

[[2, 3], [4, 1], [8, 4], [3, 2]]
Related