0

for the most part of my day i've been trying to find a way to solve this. I'm trying to find a way to find all keys in my json code that have the key "price" and if they do, populate a dictionary or something with the price and the name of each item that has a price. This is the simplified json, please note that the "price" keys can also be further nested. I'm trying to search the whole json code for the key:

{
  "status": "success",
  "data": {
    "top_products": {
      "products": [
        {
          "price": 3,
          "name": "Apple"
        },
        {
          "price": 2,
          "name": "Banana"
        }
      ]
    },
    "products": {
      "fruits": {
        "list": [
          {
            "price": 4,
            "name": "Pear"
          },
          {
            "name": "Kiwi"
          },
          {
            "price": 4,
            "name": "Pineapple"
          },
          {
            "name": "Cherry"
          }
        ]
      },
      "veggies": {
        "list": [
          {
            "price": 3,
            "name": "cucumber"
          },
          {
            "name": "tomato"
          },
          {
            "price": 2,
            "name": "onion"
          },
          {
            "name": "green pepper"
          }
        ]
      }
    }
  }
}

Here is what i've managed to get working so far (didnt come up with this, found it in some other response):

def findkeys(node, kv):
    if isinstance(node, list):
        for i in node:
            for x in findkeys(i, kv):
               yield x
    elif isinstance(node, dict):
        if kv in node:
            yield node[kv]
        for j in node.values():
            for x in findkeys(j, kv):
                yield x

print(list(findkeys(jsonResponse, 'price')))

The first part works, it returns all the keys that have a price. I'm trying to figure out a way to also write the "name" key for all the prices, preferably into a dictionary. Whats the best approach to do this? Thanks, Rob

robs
  • 649
  • 4
  • 13
  • 28

1 Answers1

2

Use the following code, if there are only unique items:

def create_db(data, find, other):
    db = {}
    def recurse(data):
        if isinstance(data, list):
            for elem in data:
                recurse(elem)
        elif isinstance(data, dict):
            if find in data:
                db[data[other]] = data[find]      
            for k, v in data.items():
                recurse(v)
    recurse(data)
    return db

>>> create_db(data, 'price', 'name')
{'Apple': 3, 'Banana': 2, 'Pear': 4, 'Pineapple': 4, 'cucumber': 3, 'onion': 2}

Else:

def create_db(data, find, other):
    db = {}
    ctr = {}
    def recurse(data):
        if isinstance(data, list):
            for elem in data:
                recurse(elem)
        elif isinstance(data, dict):
            if find in data:
                if data[other] in ctr:
                    ctr[data[other]] = str(int(ctr[data[other]] or '1') + 1)
                else:
                    ctr[data[other]] = ''
                key = data[other] + ctr[data[other]]
                db[key] = data[find]      
            for k, v in data.items():
                recurse(v)
    recurse(data)
    return db

For example, if data had two Apples:

data = {'status': 'success',
 'data': {'top_products': {'products': [{'price': 3, 'name': 'Apple'},
    {'price': 4, 'name': 'Apple'},
    {'price': 2, 'name': 'Banana'}]}}}

# Second approach will add a serial number to each duplicate item
>>> create_db(data, 'price', 'name')
{'Apple': 3, 'Apple2': 4, 'Banana': 2}

For easier access in case of duplicates, you can create a nested dict:

def create_db(data, find, other):
    db = {}
    def recurse(data):
        if isinstance(data, list):
            for elem in data:
                recurse(elem)
        elif isinstance(data, dict):
            if find in data:
                if data[other] in db:
                    if isinstance(db[data[other]], dict):
                        db[data[other]][len(db[data[other]]) + 1] = data[other]
                    else:
                        db[data[other]] = {0: db.pop(data[other]), 1: data[find]}
                else:
                    db[data[other]] = data[find]      
            for k, v in data.items():
                recurse(v)
    recurse(data)
    return db

# For the data in above approach:
>>> create_db(data, 'price', 'name')
{'Apple': {0: 3, 1: 4}, 'Banana': 2}
Sayandip Dutta
  • 15,602
  • 4
  • 23
  • 52
  • 1
    Wow Sayandip thank you so much! Just tested it with the first example and it worked!! You are a rockstar!!! – robs Feb 14 '21 at 22:19