遍历嵌套字典并在Python中获取路径?

比尔盖*_*尔盖子 2 python recursion dictionary

我有一本字典,例如:

{
   "checksum": "b884cbfb1a6697fa9b9eea9cb2054183",
   "roots": {
      "bookmark_bar": {
         "children": [ {
            "date_added": "12989159740428363",
            "id": "4",
            "name": "test2",
            "type": "url",
            "url": "chrome://bookmarks/#1"
         } ],
         "date_added": "12989159700896551",
         "date_modified": "12989159740428363",
         "id": "1",
         "name": "bookmark_bar",
         "type": "folder"
      },
      "other": {
         "children": [ {
            "date_added": "12989159740428363",
            "id": "4",
            "name": "test",
            "type": "url",
            "url": "chrome://bookmarks/#1"
         } ],
         "date_added": "12989159700896557",
         "date_modified": "0",
         "id": "2",
         "name": "aaa",
         "type": "folder"
      },
      "synced": {
         "children": [  ],
         "date_added": "12989159700896558",
         "date_modified": "0",
         "id": "3",
         "name": "bbb",
         "type": "folder"
      }
   },
   "version": 1
}
Run Code Online (Sandbox Code Playgroud)

一切都始于“根”,它们有两种类型的数据:URL和文件夹,它们是字典。如果是文件夹,则必须具有键“ children”,该键的值是一个列表,我们可以在其中放置更多URL和文件夹。

现在,我想遍历此嵌套字典,以获取所有子文件夹中的URL,因此我编写了一个函数:

def traverse(dic):
    for i in dic:
        if i['type'] == 'folder':
            for j in traverse(i['children']):
                yield j
        elif i['type'] == 'url':
            yield i
Run Code Online (Sandbox Code Playgroud)

我可以这样使用它:

traverse(dictionary['roots']['bookmark_bar']['children'])
Run Code Online (Sandbox Code Playgroud)

它运作完美。但是它只是生成URL的字典,我不知道它在哪里。我也想走这条路。我该怎么做?

小智 5

我的用例与您稍有不同:我需要将表示客户端设置的可变深度JSON结构展平为键值对,以存储在数据库中。我无法获得jsbueno的工作答案,并且由于我还需要一些可以处理案例而又没有明确列出或包含孩子的案例,因此我对其进行了修改以满足我的需要:

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
Run Code Online (Sandbox Code Playgroud)

最终结果是我可以将这样的JSON字符串传递给我的脚本(具有可变深度),该脚本将其转换为嵌套的字典:

{
  "servers": {
    "uat": {
      "pkey": true,
      "user": "testval",
      "pass": true
    },
    "dev": {
      "pkey": true,
      "user": "testval",
      "pass": true
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在上面运行生成器将创建一个类似以下内容的列表:

([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)
Run Code Online (Sandbox Code Playgroud)

其中,使用类似:

for x in traverse(outobj):
    pprint(('.'.join(x[0]),x[1]))
Run Code Online (Sandbox Code Playgroud)

然后可以将其转换成我想要的键值对格式:

(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)
Run Code Online (Sandbox Code Playgroud)

我知道在接受接受的答案后我会以这种方式发布信息,但是由于接受的答案对我不起作用,因此,这种与结构无关的略显版本可能会对其他人有所帮助!