我正在尝试更新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],我假设它是我试图接下来的元素的索引。
答案 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
}
]
}
]
}