【问题标题】:How can I select deeply nested key:values from dictionary in python如何从python中的字典中选择深度嵌套的键:值
【发布时间】:2018-04-12 17:35:41
【问题描述】:

我从网站下载了一个 json 数据,我想从嵌套的 json 中选择特定的键:值。我将 json 转换为 python 字典。然后我使用字典理解来选择嵌套的 key:values ,但是嵌套太多了,我相信有比单独扩展每个字典更好的方法。我在我的方法中看到了冗余。你能推荐一个更好的方法吗?

{
    "success": true,
    "payload": {
        "tag": {
            "slug": "python",
            "name": "Python",
            "postCount": 10590,
            "virtuals": {
                "isFollowing": false
            }
        },
        "metadata": {
            "followerCount": 18053,
            "postCount": 10590,
            "coverImage": {
                "id": "1*O3-jbieSsxcQFkrTLp-1zw.gif",
                "originalWidth": 550,
                "originalHeight": 300
            }
        }
    }
}    

我的方法:

从日期时间导入日期时间,时间增量

import json,re

data=r'data.json'
#reads json and converts to dictionary
def js_r(data):
    with open(data, encoding='Latin-1') as f_in:
        return json.load(f_in)

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])
if __name__=="__main__":
    my_dict=js_r(data)
    print ( "This is dictionary for python tag",my_dict)
    keys=my_dict.keys()
    print ("This is the dictionary keys",my_dict.keys())
    my_payload=list(find_key(my_dict,'title'))
    print ("These are my payload",my_payload)
    my_post=iter_dict(my_dict,'User','id')
    print(list(my_post))

【问题讨论】:

  • 你可以在这里找到我感兴趣的代码:stackoverflow.com/q/41777880/4014959
  • @PM 2Ring 如果我给函数我知道的嵌套键,它会给我嵌套在其中的字典吗?如果这是一个微不足道的问题,我深表歉意。
  • @wwii 也许吧。老实说,我并不完全清楚 Kaleab 在做什么。他真的要创建payload_dictpaging_dict 以供将来使用吗?还是他创建它们只是因为他认为他必须这样做才能获得他想要的数据?
  • 我建议使用我链接的代码,看看它是否符合您的要求。也看看stackoverflow.com/questions/46700975/…
  • @PM 2Ring 实际上,我的目的是深入巢穴,payload_dict 和 paging_dict 不是最终结果,我想进一步降低用户密钥,这就是为什么我认为它是多余的方式。

标签: python json dictionary key


【解决方案1】:

我建议您使用python-benedict,这是一个可靠的python dict 子类,具有完整的keypath 支持 和许多实用方法。

它提供多种格式的 IO 支持,包括json

你可以直接从json文件初始化:

from benedict import benedict

d = benedict.from_json('data.json')

现在你的 dict 有了 keypath 支持:

print(d['payload.metadata.coverImage.id'])

# or use get to avoid a possible KeyError
print(d.get('payload.metadata.coverImage.id'))

安装:pip install python-benedict

这里是库存储库和文档: https://github.com/fabiocaccamo/python-benedict

注意:我是这个项目的作者

【讨论】:

    【解决方案2】:

    以下是您如何使用来自Functions that help to understand json(dict) structurefind_keys 生成器从该JSON 数据中获取“id”值,以及我随机选择的其他一些键。此代码从字符串中获取 JSON 数据,而不是从文件中读取。

    import json
    
    json_data = '''\
    {
        "success": true,
        "payload": {
            "tag": {
                "slug": "python",
                "name": "Python",
                "postCount": 10590,
                "virtuals": {
                    "isFollowing": false
                }
            },
            "metadata": {
                "followerCount": 18053,
                "postCount": 10590,
                "coverImage": {
                    "id": "1*O3-jbieSsxcQFkrTLp-1zw.gif",
                    "originalWidth": 550,
                    "originalHeight": 300
                }
            }
        }
    }
    '''
    
    data = r'data.json'
    
    #def js_r(data):
        #with open(data, encoding='Latin-1') as f_in:
            #return json.load(f_in)
    
    # Read the JSON from the inline json_data string instead of from the data file
    def js_r(data):
        return json.loads(json_data)
    
    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])
    
    if __name__=="__main__":
        # Read the JSON data
        my_dict = js_r(data)
        print("This is the JSON data:")
        print(json.dumps(my_dict, indent=4), "\n")
    
        # Find the id key
        keypath, val = next(find_key(my_dict, "id"))
        print("This is the id: {!r}".format(val))
        print("These are the keys that lead to the id:", keypath, "\n")
    
        # Find the name, followerCount, originalWidth, and originalHeight
        print("Here are some more (key, value) pairs")
        keys = ("name", "followerCount", "originalWidth", "originalHeight")
        for k in keys:
            keypath, val = next(find_key(my_dict, k))
            print("{!r}: {!r}".format(k, val))
    

    输出

    This is the JSON data:
    {
        "success": true,
        "payload": {
            "tag": {
                "slug": "python",
                "name": "Python",
                "postCount": 10590,
                "virtuals": {
                    "isFollowing": false
                }
            },
            "metadata": {
                "followerCount": 18053,
                "postCount": 10590,
                "coverImage": {
                    "id": "1*O3-jbieSsxcQFkrTLp-1zw.gif",
                    "originalWidth": 550,
                    "originalHeight": 300
                }
            }
        }
    } 
    
    This is the id: '1*O3-jbieSsxcQFkrTLp-1zw.gif'
    These are the keys that lead to the id: ['payload', 'metadata', 'coverImage', 'id'] 
    
    Here are some more (key, value) pairs
    'name': 'Python'
    'followerCount': 18053
    'originalWidth': 550
    'originalHeight': 300
    

    顺便说一句,JSON 通常使用 UTF 编码,而不是 Latin-1。默认编码是 UTF-8,如果可能,您应该使用它。

    【讨论】:

      猜你喜欢
      • 2017-04-30
      • 2021-12-29
      • 2011-02-01
      • 2021-08-03
      • 2018-11-30
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多