在 Python 中导航嵌套 JSON 的最佳方式?

Best way to navigate a nested JSON in Python?

我尝试了不同的 for 循环来遍历此 JSON,但我不知道该怎么做。我有一个数字列表,想将它与每个“数据”对象(例如 Aatrox、Ahri、Akali 等)下的“键”值进行比较,如果数字匹配,则存储“名称” 另一个列表中的值。

示例: listOfNumbers = [266, 166, 123, 283]

266 和 166 将分别匹配 Aatrox 和 Akshan 对象中的“键”,所以我想提取该名称并将其存储在列表中。

我知道这个 JSON 主要通过键值访问而不是索引,所以我不确定我将如何遍历 for 循环中的所有“数据”对象。

JSON 我正在引用:

{
  "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
      }
    }
  }
}

您只需遍历字典的值,检查 'key' 项的值是否在您的列表中,如果是,则将 'name' 项的值附加到您的列表中输出列表。

jsonObj 成为您在问题中提出的 JSON 对象。那么这段代码应该可以工作:

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

JSON Python 中的对象只是字典。所以,你最好熟悉一下 Python 的 dict.

假设您的完整 json 在 all_data 中,您将获得与键 'data' 对应的值 all_data['data']。这又是一个字典,您可以使用 returns 键值对的项目迭代它。

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

先把键值映射成字典,然后在里面搜索。

代码注释中的进一步解释:

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]

这是一个适用于你的 json 的版本,我更新后使其有效。

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

如果您想匹配数字,您还必须 int 您的值。

输出

['Aatrox', 'Akshan']

另一种方法是将您的 dict 转换为 json 并转换为 pandas 数据框并对其进行过滤。这是一个函数,它将展平任何嵌套的 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

有了它,您可以执行以下操作:

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

哪个return一个数据帧:

 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]

然后您可以根据需要对其进行过滤:

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

有很多解决方案 你也可以试试这个 我认为它非常适合您的解决方案

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)