如何修改嵌套Json的密钥

时间:2017-10-12 03:33:43

标签: python json dictionary

我正在尝试更新JSON对象的键,如下所示:

results = 
 {  
   'Game':12345,
   'stats':[  
      {  
         'detail':[  
            {  
               'goals':4,
               'refs':{  
                  'number':0

我目前正在手动更新每个密钥,如下所示

##update Game to newValue
results['newValue'] = results['Game']
    del results['Game']

## update nested key "goals" to "goals_against"
results['stats'][0]['detail'][0]['goals_against'] = results['stats'][0]['detail'][0]['goals']
    del results['stats'][0]['detail'][0]['goals']

必须有更好的方法,因为我发现自己必须更新结果上的多个键。例如,我还想将“number”键更新为“assis_ref”。

我知道如果json文件是“简单”的话,如何更新密钥:即如果我能这样做:

result['stats']['details']['refs']

然而,'stats'和'details'需要它旁边的[0],我假设它是我试图接下来的元素的索引。

1 个答案:

答案 0 :(得分:0)

导航和修改从JSON对象派生的深层嵌套对象可能会很痛苦。在Functions that help to understand json(dict) structure中,我发布了允许您导航此类对象的代码。请阅读该答案中的解释。在这个答案中,我将展示如何使用该代码修改此类对象中的字典键。

简而言之,find_key是一个递归生成器,它将查找具有给定名称的所有键。您可以使用next函数获取第一个(或唯一的)匹配名称。如果您需要使用多个具有相同名称的密钥,请在find_key循环中调用for

find_key产生的每个值都是dict键列表,列表索引需要达到所需的键。

from json import dumps

def find_key(obj, key):
    if isinstance(obj, dict):
        yield from iter_dict(obj, key, [])
    elif isinstance(obj, list):
        yield from iter_list(obj, key, [])

def iter_dict(d, key, indices):
    for k, v in d.items():
        if k == key:
            yield indices + [k], v
        if isinstance(v, dict):
            yield from iter_dict(v, key, indices + [k])
        elif isinstance(v, list):
            yield from iter_list(v, key, indices + [k])

def iter_list(seq, key, indices):
    for k, v in enumerate(seq):
        if isinstance(v, dict):
            yield from iter_dict(v, key, indices + [k])
        elif isinstance(v, list):
            yield from iter_list(v, key, indices + [k])


results = {
    "Game": 12345,
    "stats": [
        {
            "detail": [
                {
                    "goals": 4,
                    "refs": {
                        "number": 0
                    }
                }
            ]
        }
    ]
}

# Change oldkey to newkey      
oldkey, newkey = 'goals', 'goals_against'
# Find the first occurrence of the oldkey
seq, val = next(find_key(results, oldkey))
print('seq:', seq, 'val:', val)

# Get the object that contains the oldkey 
obj = results
for k in seq[:-1]:
    obj = obj[k]

# Change the key
obj[newkey] = obj.pop(oldkey)

print(dumps(results, indent=4))

<强>输出

seq: ['stats', 0, 'detail', 0, 'goals'] val: 4
{
    "Game": 12345,
    "stats": [
        {
            "detail": [
                {
                    "refs": {
                        "number": 0
                    },
                    "goals_against": 4
                }
            ]
        }
    ]
}