帮助理解json(dict)structu的函数

2024-07-05 15:04:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我还没找到一个办法。 假设我收到这样一个JSON对象:

{'1_data':{'4_data':[{'5_data':'hooray'}, {'3_data':'hooray2'}], '2_data':[]}}

很难说,我应该如何从3\u数据键中获取值:data['1_data']['4_data'][1]['3_data']

我知道pprint,它有助于理解一点结构。 但有时数据量很大,而且需要时间

有什么方法可以帮我吗?在


Tags: 数据对象方法jsondata时间结构pprint
1条回答
网友
1楼 · 发布于 2024-07-05 15:04:26

这里有一系列递归生成器,可用于搜索由dict和list组成的对象。find_key生成一个元组,其中包含字典键的列表和指向您传入的键的列表索引;该元组还包含与该键关联的值。因为它是一个生成器,如果对象包含多个匹配键(如果需要的话),它将找到所有匹配的键。在

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])

# test

data = {
    '1_data': {
        '4_data': [
            {'5_data': 'hooray'},
            {'3_data': 'hooray2'}
        ], 
        '2_data': []
    }
}

for t in find_key(data, '3_data'):
    print(t)

输出

^{pr2}$

要获得一个单键列表,可以将find_key传递给next函数。如果您想使用一个键列表来获取相关的值,您可以使用一个简单的for循环。在

seq, val = next(find_key(data, '3_data'))
print('seq:', seq, 'val:', val)

obj = data
for k in seq:
    obj = obj[k]
print('obj:', obj, obj == val)

输出

seq: ['1_data', '4_data', 1, '3_data'] val: hooray2
obj: hooray2 True

如果键可能丢失,那么给next一个适当的默认元组。例如:

seq, val = next(find_key(data, '6_data'), ([], None))
print('seq:', seq, 'val:', val)
if seq:
    obj = data
    for k in seq:
        obj = obj[k]
    print('obj:', obj, obj == val)

输出

seq: [] val: None

注意,这段代码是为python3编写的。要在python2上运行它,您需要替换所有yield from语句,例如replace

yield from iter_dict(obj, key, [])

for u in iter_dict(obj, key, []):
    yield u

工作原理

要理解这段代码是如何工作的,您需要熟悉recursion和Python generators。您可能还会发现这个页面很有帮助:Understanding Generators in Python;在线上还有各种Python生成器教程。在

json.loadjson.loads返回的Python对象通常是dict,但也可以是列表。我们将该对象作为obj参数和我们要定位的key字符串一起传递给find_key生成器。find_key然后根据需要调用iter_dict或{},向它们传递对象、键和空列表indices,该列表用于收集dict键并列出指向所需键的索引。在

iter_dict在其ddict arg的顶层迭代每个(k,v)对。如果k与我们要查找的键匹配,则生成当前的indices列表,并附加k以及相关联的值。因为iter_dict是递归的,所以产生的(索引列表,值)对被传递到上一级递归,最终到达find_key,然后传递到调用find_key的代码。请注意,这是递归的“基本情况”:它是代码的一部分,决定这个递归路径是否指向我们想要的键。如果递归路径从未找到与我们要查找的键匹配的键,那么该递归路径不会向indices添加任何内容,它将终止而不会产生任何结果。在

如果当前的v是dict,那么我们需要检查它包含的所有(key,value)对。我们通过递归调用iter_dict,传递v是它的起始对象和当前的indices列表。如果当前的v是一个列表,我们改为将其称为iter_list,并传递相同的参数。在

iter_list的工作原理与iter_dict相似,除了列表没有任何键,它只包含值,所以我们不执行k == key测试,我们只递归到原始列表中包含的任何dict或list。在

这个过程的最终结果是,当我们迭代find_key时,我们会得到一对(索引,值),其中每个indices列表是dict键的序列和成功地用我们所需的键终止在dict项中的索引,value是与该特定键关联的值。在

如果您想看看这段代码的其他使用示例,请参见how to modify the key of a nested JsonHow can I select deeply nested key:values from dictionary in python。在

同时看看我的新的、更精简的^{}函数。在

相关问题 更多 >