Home > Software engineering >  Best way to navigate a nested JSON in Python?
Best way to navigate a nested JSON in Python?

Time:01-21

I have tried different for loops trying to iterate through this JSON and I cant figure out how to do it. I have a list of numbers and want to compare it to the "key" values under each object of "data" (For example, Aatrox, Ahri, Akali, and so on) and if the numbers match store the "name" value in another list.

Example: listOfNumbers = [266, 166, 123, 283]

266 and 166 would match the "key" in the Aatrox and Akshan objects respectively so I would want to pull that name and store it in a list.

I understant this JSON is mostly accessed by key values rather than being indexed so Im not sure how I would iterate through all the "data" objects in a for loop(s).

JSON im referencing:

{
  "type": "champion",
  "format": "standAloneComplex",
  "version": "12.2.1",
  "data": {
    "Aatrox": {
      "version": "12.2.1",
      "id": "Aatrox",
      "key": "266",
      "name": "Aatrox",
      "title": "the Darkin Blade",
      "blurb": "Once honored defenders of Shurima against the Void, Aatrox and his brethren would eventually become an even greater threat to Runeterra, and were defeated only by cunning mortal sorcery. But after centuries of imprisonment, Aatrox was the first to find...",
      "info": {
        "attack": 8,
        "defense": 4,
        "magic": 3,
        "difficulty": 4
      },
      "image": {
        "full": "Aatrox.png",
        "sprite": "champion0.png",
        "group": "champion",
        "x": 0,
        "y": 0,
        "w": 48,
        "h": 48
      },
      "tags": [
        "Fighter",
        "Tank"
      ],
      "partype": "Blood Well",
      "stats": {
        "hp": 580,
        "hpperlevel": 90,
        "mp": 0,
        "mpperlevel": 0,
        "movespeed": 345,
        "armor": 38,
        "armorperlevel": 3.25,
        "spellblock": 32,
        "spellblockperlevel": 1.25,
        "attackrange": 175,
        "hpregen": 3,
        "hpregenperlevel": 1,
        "mpregen": 0,
        "mpregenperlevel": 0,
        "crit": 0,
        "critperlevel": 0,
        "attackdamage": 60,
        "attackdamageperlevel": 5,
        "attackspeedperlevel": 2.5,
        "attackspeed": 0.651
      }
    },
    "Ahri": {
      "version": "12.2.1",
      "id": "Ahri",
      "key": "103",
      "name": "Ahri",
      "title": "the Nine-Tailed Fox",
      "blurb": "Innately connected to the latent power of Runeterra, Ahri is a vastaya who can reshape magic into orbs of raw energy. She revels in toying with her prey by manipulating their emotions before devouring their life essence. Despite her predatory nature...",
      "info": {
        "attack": 3,
        "defense": 4,
        "magic": 8,
        "difficulty": 5
      },
      "image": {
        "full": "Ahri.png",
        "sprite": "champion0.png",
        "group": "champion",
        "x": 48,
        "y": 0,
        "w": 48,
        "h": 48
      },
      "tags": [
        "Mage",
        "Assassin"
      ],
      "partype": "Mana",
      "stats": {
        "hp": 526,
        "hpperlevel": 92,
        "mp": 418,
        "mpperlevel": 25,
        "movespeed": 330,
        "armor": 21,
        "armorperlevel": 3.5,
        "spellblock": 30,
        "spellblockperlevel": 0.5,
        "attackrange": 550,
        "hpregen": 5.5,
        "hpregenperlevel": 0.6,
        "mpregen": 8,
        "mpregenperlevel": 0.8,
        "crit": 0,
        "critperlevel": 0,
        "attackdamage": 53,
        "attackdamageperlevel": 3,
        "attackspeedperlevel": 2,
        "attackspeed": 0.668
      }
    },
    "Akali": {
      "version": "12.2.1",
      "id": "Akali",
      "key": "84",
      "name": "Akali",
      "title": "the Rogue Assassin",
      "blurb": "Abandoning the Kinkou Order and her title of the Fist of Shadow, Akali now strikes alone, ready to be the deadly weapon her people need. Though she holds onto all she learned from her master Shen, she has pledged to defend Ionia from its enemies, one...",
      "info": {
        "attack": 5,
        "defense": 3,
        "magic": 8,
        "difficulty": 7
      },
      "image": {
        "full": "Akali.png",
        "sprite": "champion0.png",
        "group": "champion",
        "x": 96,
        "y": 0,
        "w": 48,
        "h": 48
      },
      "tags": [
        "Assassin"
      ],
      "partype": "Energy",
      "stats": {
        "hp": 500,
        "hpperlevel": 105,
        "mp": 200,
        "mpperlevel": 0,
        "movespeed": 345,
        "armor": 23,
        "armorperlevel": 3.5,
        "spellblock": 37,
        "spellblockperlevel": 1.25,
        "attackrange": 125,
        "hpregen": 9,
        "hpregenperlevel": 0.9,
        "mpregen": 50,
        "mpregenperlevel": 0,
        "crit": 0,
        "critperlevel": 0,
        "attackdamage": 62,
        "attackdamageperlevel": 3.3,
        "attackspeedperlevel": 3.2,
        "attackspeed": 0.625
      }
    },
    "Akshan": {
      "version": "12.2.1",
      "id": "Akshan",
      "key": "166",
      "name": "Akshan",
      "title": "the Rogue Sentinel",
      "blurb": "Raising an eyebrow in the face of danger, Akshan fights evil with dashing charisma, righteous vengeance, and a conspicuous lack of shirts. He is highly skilled in the art of stealth combat, able to evade the eyes of his enemies and reappear when they...",
      "info": {
        "attack": 0,
        "defense": 0,
        "magic": 0,
        "difficulty": 0
      },
      "image": {
        "full": "Akshan.png",
        "sprite": "champion0.png",
        "group": "champion",
        "x": 144,
        "y": 0,
        "w": 48,
        "h": 48
      },
      "tags": [
        "Marksman",
        "Assassin"
      ],
      "partype": "Mana",
      "stats": {
        "hp": 560,
        "hpperlevel": 90,
        "mp": 350,
        "mpperlevel": 40,
        "movespeed": 330,
        "armor": 26,
        "armorperlevel": 3,
        "spellblock": 30,
        "spellblockperlevel": 0.5,
        "attackrange": 500,
        "hpregen": 3.75,
        "hpregenperlevel": 0.65,
        "mpregen": 8.175,
        "mpregenperlevel": 0.7,
        "crit": 0,
        "critperlevel": 0,
        "attackdamage": 52,
        "attackdamageperlevel": 3.5,
        "attackspeedperlevel": 4,
        "attackspeed": 0.638
      }
    }
  }
}

CodePudding user response:

You simply iterate over the values of the dictionary, check whether the value of the 'key' item is in your list and if that's the case, append the value of the 'name' item to your output list.

Let jsonObj be your JSON object presented in your question. Then this code should work:

listOfNumbers = [266, 166, 123, 283]
names = []
for value in jsonObj['data'].values():
    if value['key'] in listOfNumbers:
        names.append(value['name'])

JSON objects in Python are just dictionaries. So, you better familiarize yourself with Python's dict.

CodePudding user response:

Lets say you full json is in all_data, you would get the values corresponding to the key 'data' as all_data['data']. This is again a dictionary, and you iterate over that using items which returns key,value pairs.

names = [value['name'] for name, value in all_data['data'].items() if value['key'] in listOfNumbers]

CodePudding user response:

First convert into a dictionary mapping keys to names, and then search in it.

Further explanation in the code's comments:

import json

keys = [266, 166, 123, 283]

# First, we need to parse the JSON string into a Python dictionary
# Skip this if you already have a dictionary.
data = json.loads(raw_json)

# Then map keys to names
key_to_id = {int(obj["key"]): obj["id"] for obj in data["data"].values()}

# Lastly, extract the names we want
ids = [key_to_id[key] for key in keys]

CodePudding user response:

Another approach is to transform your dict into a json into a pandas dataframe and filter it. Here is a function that will flatten any nested json:

from flatten_json import flatten
import pandas as pd


def flatten_nested_json_df(df):
    df = df.reset_index()
    s = (df.applymap(type) == list).all()
    list_columns = s[s].index.tolist()
    
    s = (df.applymap(type) == dict).all()
    dict_columns = s[s].index.tolist()

    
    while len(list_columns) > 0 or len(dict_columns) > 0:
        new_columns = []

        for col in dict_columns:
            horiz_exploded = pd.json_normalize(df[col]).add_prefix(f'{col}.')
            horiz_exploded.index = df.index
            df = pd.concat([df, horiz_exploded], axis=1).drop(columns=[col])
            new_columns.extend(horiz_exploded.columns) # inplace

        for col in list_columns:
            #print(f"exploding: {col}")
            df = df.drop(columns=[col]).join(df[col].explode().to_frame())
            new_columns.append(col)

        s = (df[new_columns].applymap(type) == list).all()
        list_columns = s[s].index.tolist()

        s = (df[new_columns].applymap(type) == dict).all()
        dict_columns = s[s].index.tolist()
    return df

Having this you can do the following:

json = json.dumps(data) 
df = pd.json_normalize(data)
flatten_nested_json_df(df)

which return a dataframe:

 index      type             format version data.Aatrox.version  \
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
..    ...       ...                ...     ...                 ...   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   
0       0  champion  standAloneComplex  12.2.1              12.2.1   

   data.Aatrox.id data.Aatrox.key data.Aatrox.name data.Aatrox.title  \
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
..            ...             ...              ...               ...   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   
0          Aatrox             266           Aatrox  the Darkin Blade   

                                    data.Aatrox.blurb  ...  \
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
..                                                ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   
0   Once honored defenders of Shurima against the ...  ...   

    data.Akshan.stats.crit  data.Akshan.stats.critperlevel  \
0                        0                               0   
0                        0                               0   
0                        0                               0   
0                        0                               0   
0                        0                               0   
..                     ...                             ...   
0                        0                               0   
0                        0                               0   
0                        0                               0   
0                        0                               0   
0                        0                               0   

    data.Akshan.stats.attackdamage  data.Akshan.stats.attackdamageperlevel  \
0                               52                                     3.5   
0                               52                                     3.5   
0                               52                                     3.5   
0                               52                                     3.5   
0                               52                                     3.5   
..                             ...                                     ...   
0                               52                                     3.5   
0                               52                                     3.5   
0                               52                                     3.5   
0                               52                                     3.5   
0                               52                                     3.5   

   data.Akshan.stats.attackspeedperlevel data.Akshan.stats.attackspeed  \
0                                      4                         0.638   
0                                      4                         0.638   
0                                      4                         0.638   
0                                      4                         0.638   
0                                      4                         0.638   
..                                   ...                           ...   
0                                      4                         0.638   
0                                      4                         0.638   
0                                      4                         0.638   
0                                      4                         0.638   
0                                      4                         0.638   

   data.Aatrox.tags  data.Ahri.tags  data.Akali.tags  data.Akshan.tags  
0           Fighter            Mage         Assassin          Marksman  
0           Fighter            Mage         Assassin          Assassin  
0           Fighter            Mage         Assassin          Marksman  
0           Fighter            Mage         Assassin          Assassin  
0           Fighter            Mage         Assassin          Marksman  
..              ...             ...              ...               ...  
0              Tank        Assassin         Assassin          Assassin  
0              Tank        Assassin         Assassin          Marksman  
0              Tank        Assassin         Assassin          Assassin  
0              Tank        Assassin         Assassin          Marksman  
0              Tank        Assassin         Assassin          Assassin  

[8192 rows x 160 columns]

YOu can then filter it on whatever you want:

listOfNumbers = ['266', '166', '123', '283']
df_sub = df[df['data.Aatrox.key'].isin(listOfNumbers)]

CodePudding user response:

Here is one that works with your json that I updated to make valid.

d = json.loads(j)
nums = [266, 166, 123, 283]
names = [v["name"] for v in d["data"].values() if int(v["key"]) in nums]

You also have to int your values if you want to match numbers.

output

['Aatrox', 'Akshan']

CodePudding user response:

There have lot's of solution you can try this one too I think it will perfectly work for your solution

import json

#Load your json or manually declare your json here 
with open('yourfile.json') as f:
  Data= json.load(f) 

#This the main code for accesing the value and get the result 
Temp_Data=Data['data']
result_list=[]
listOfNumbers =[266,166,123,283]
for data,data_info in Temp_Data.items():
    key_value=int(Temp_Data[data]['key'])
    if key_value in listOfNumbers:
        result_list.append(data)
print(result_list)
  •  Tags:  
  • Related