Traverse a nested dictionary and get the path in Python?

后端 未结 2 1379
南旧
南旧 2020-12-03 16:12

I have a dictionary like:

{
   \"checksum\": \"b884cbfb1a6697fa9b9eea9cb2054183\",
   \"roots\": {
      \"bookmark_bar\": {
         \"children\": [ {
              


        
相关标签:
2条回答
  • 2020-12-03 17:00

    I had a slightly different use case from you: I needed to flatten a variable depth JSON structure representing client settings into key-value pairs for storage in a database. I couldn't get jsbueno's answer to work, and since I also needed something that could handle cases without children being explicitly listing or contained, I modified it to suit my needs:

    def traverse(dic, path=None):
        if not path:
            path=[]
        if isinstance(dic,dict):
            for x in dic.keys():
                local_path = path[:]
                local_path.append(x)
                for b in traverse(dic[x], local_path):
                     yield b
        else: 
            yield path,dic
    

    The end result is i can pass in a JSON string like this to my script (with variable depths), which converts it to nested dicts:

    {
      "servers": {
        "uat": {
          "pkey": true,
          "user": "testval",
          "pass": true
        },
        "dev": {
          "pkey": true,
          "user": "testval",
          "pass": true
        }
      }
    }
    

    running the generator above against it creates a list that pretty-prints like this:

    ([u'servers', u'uat', u'pkey'], True)
    ([u'servers', u'uat', u'user'], u'testval')
    ([u'servers', u'uat', u'pass'], True)
    ([u'servers', u'dev', u'pkey'], True)
    ([u'servers', u'dev', u'user'], u'testval')
    ([u'servers', u'dev', u'pass'], True)
    

    Which, using something like:

    for x in traverse(outobj):
        pprint(('.'.join(x[0]),x[1]))
    

    can then be transformed into the key-value pair format I want like so:

    (u'servers.uat.pkey', True)
    (u'servers.uat.user', u'testval')
    (u'servers.uat.pass', True)
    (u'servers.dev.pkey', True)
    (u'servers.dev.user', u'testval')
    (u'servers.dev.pass', True)
    

    I know I'm posting this way after the accepted answer was accepted, but since the accepted answer didn't work for me, maybe this slight more structure-agnostic version will help someone else!

    0 讨论(0)
  • 2020-12-03 17:06

    Not shure if I got what you want, but you might want to do this:

    def traverse(dic, path=None):
        if not path:
            path = []
        for i in dic:
            local_path = path[:].append(i)
            if i['type'] == 'folder':
                for j in traverse(i['children'], local_path):
                    yield j, local_path
            elif i['type'] == 'url':
                yield i, local_path
    

    Now your function yields the item and a sequence of the keys to get to the item at a certain location.

    0 讨论(0)
提交回复
热议问题