为了账号安全,请及时绑定邮箱和手机立即绑定

帮助理解json(dict)结构的函数

帮助理解json(dict)结构的函数

呼啦一阵风 2019-12-05 15:49:25
我还没有找到解决方法。假设我收到这样的JSON对象:{'1_data':{'4_data':[{'5_data':'hooray'}, {'3_data':'hooray2'}], '2_data':[]}}很难立即说出,我该如何从3_data键中获取价值:data['1_data']['4_data'][1]['3_data']我知道pprint,它有助于有点了解结构。但是有时数据量巨大,并且需要时间有什么方法可以帮助我吗?
查看完整描述

1 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

这是一组递归生成器,可用于搜索由字典和列表组成的对象。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)

输出


(['1_data', '4_data', 1, '3_data'], 'hooray2')

要获取单个键列表,可以传递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

请注意,此代码是针对Python 3的。要在Python 2上运行,您需要替换所有yield from语句,例如replace


yield from iter_dict(obj, key, [])


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

    yield u

怎么运行的

要了解此代码的工作原理,您需要熟悉递归和Python 生成器。您可能还会发现此页面有帮助:了解Python中的生成器;在线上也有各种Python生成器教程。


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


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


如果当前v是一个字典,那么我们需要检查它包含的所有(键,值)对。我们通过对进行递归调用来实现iter_dict,将v其作为起始对象和当前indices列表进行传递。如果当前v是一个列表,我们改为调用iter_list,将相同的参数传递给它。


iter_listiter_dict除了列表不包含任何键,它只包含值外,其工作方式与之类似。因此,我们不执行k == key测试,而是递归到原始列表包含的所有字典或列表。


该过程的最终结果是,当我们进行迭代时,find_key我们获得(索引,值)对,其中每个indices列表是dict键的序列和列表索引,这些键成功地终止于带有所需键的dict项中,并且value是关联的值用那个特定的钥匙。


如果您想查看此代码的其他示例,请参阅如何修改嵌套Json的键以及如何从python的字典中选择深度嵌套的key:values。


还要看看我的新的,更简化的show_indices功能。


分享编辑


查看完整回答
反对 回复 2019-12-05
  • 1 回答
  • 0 关注
  • 317 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号