Переместить вложенный словарь и получить путь в Python?
У меня есть словарь вроде:
{
"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
}
Все начинается с "корней", у них есть два типа данных: URL и папка, это словари.
Если это папка, она должна иметь ключ "дети", значение ключа - это список, мы можем добавить в него больше 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
и я могу использовать его так:
traverse(dictionary['roots']['bookmark_bar']['children'])
Он отлично работает. Но он просто создает словарь URL-адреса, я не знаю, где он.
Я тоже хочу получить путь. Как я могу это сделать?
Ответы
Ответ 1
Не пытайся, если я получу то, что вы хотите, но вы можете сделать это:
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
Теперь ваша функция дает элемент и последовательность ключей для доступа к элементу в определенном месте.
Ответ 2
У меня был немного другой вариант использования: мне нужно было сгладить структуру 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
Конечный результат: я могу передать в строке JSON, как это, на мой script (с переменной глубиной), который преобразует его в вложенные dicts:
{
"servers": {
"uat": {
"pkey": true,
"user": "testval",
"pass": true
},
"dev": {
"pkey": true,
"user": "testval",
"pass": true
}
}
}
запуск генератора над ним создает список, который довольно печатает:
([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)
Что, используя что-то вроде:
for x in traverse(outobj):
pprint(('.'.join(x[0]),x[1]))
можно затем преобразовать в формат пары "ключ-значение", который я хочу так:
(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)
Я знаю, что я отправляю этот путь после того, как принятый ответ был принят, но так как принятый ответ не сработал у меня, возможно, эта небольшая версия с улучшенной структурой поможет кому-то еще!