Вложенное значение словаря из ключевого пути
Получить значение из вложенного словаря с помощью пути ключа, вот dict
:
json = {
"app": {
"Garden": {
"Flowers": {
"Red flower": "Rose",
"White Flower": "Jasmine",
"Yellow Flower": "Marigold"
}
},
"Fruits": {
"Yellow fruit": "Mango",
"Green fruit": "Guava",
"White Flower": "groovy"
},
"Trees": {
"label": {
"Yellow fruit": "Pumpkin",
"White Flower": "Bogan"
}
}
}
Входным параметром метода является ключевой путь с выделенными точками, из ключевого пути = "app.Garden.Flowers.white Flower" нужно напечатать "Жасмин". Мой код:
import json
with open('data.json') as data_file:
j = json.load(data_file)
def find(element, JSON):
paths = element.split(".")
# print JSON[paths[0]][paths[1]][paths[2]][paths[3]]
for i in range(0,len(paths)):
data = JSON[paths[i]]
# data = data[paths[i+1]]
print data
find('app.Garden.Flowers.White Flower',j)
Ответы
Ответ 1
Очень близко. Вы должны (как и в своем комментарии) рекурсивно пройти через главный объект JSON. Вы можете выполнить это, сохранив результат самого внешнего ключа/значения, затем используя это, чтобы получить следующий ключ/значение и т.д., Пока вы не пройдете путь.
def find(element, JSON):
paths = element.split(".")
data = JSON
for i in range(0,len(paths)):
data = data[paths[i]]
print data
Однако вам все равно нужно следить за KeyErrors.
Ответ 2
Это пример сгиба. Вы можете написать это кратко, как это:
import operator
def find(element, json):
return reduce(operator.getitem, element.split('.'), json)
Или более Pythonically (потому что reduce()
хмурится из-за плохой читаемости), как это:
def find(element, json):
keys = element.split('.')
rv = json
for key in keys:
rv = rv[key]
return rv
j = {"app": {
"Garden": {
"Flowers": {
"Red flower": "Rose",
"White Flower": "Jasmine",
"Yellow Flower": "Marigold"
}
},
"Fruits": {
"Yellow fruit": "Mango",
"Green fruit": "Guava",
"White Flower": "groovy"
},
"Trees": {
"label": {
"Yellow fruit": "Pumpkin",
"White Flower": "Bogan"
}
}
}}
print find('app.Garden.Flowers.White Flower', j)
Ответ 3
Немного поздно для вечеринки, но я был в аналогичной ситуации и нашел этот dpath module. Приятно и легко.
Надеюсь, это поможет кому-то еще:)
Ответ 4
Ваш код сильно зависит от того, нет ли точек, которые встречаются в именах ключей, которые вы могли бы контролировать, но не обязательно.
Я бы пошел на общее решение, используя список имен элементов, а затем сгенерировал список, например. разделяя пунктирный список имен клавиш:
class ExtendedDict(dict):
"""changes a normal dict into one where you can hand a list
as first argument to .get() and it will do a recursive lookup
result = x.get(['a', 'b', 'c'], default_val)
"""
def multi_level_get(self, key, default=None):
if not isinstance(key, list):
return self.get(key, default)
# assume that the key is a list of recursively accessible dicts
def get_one_level(key_list, level, d):
if level >= len(key_list):
if level > len(key_list):
raise IndexError
return d[key_list[level-1]]
return get_one_level(key_list, level+1, d[key_list[level-1]])
try:
return get_one_level(key, 1, self)
except KeyError:
return default
get = multi_level_get # if you delete this, you can still use the multi_level-get
Как только у вас есть этот класс, легко просто преобразовать свой dict и получить "Жасмин":
json = {
"app": {
"Garden": {
"Flowers": {
"Red flower": "Rose",
"White Flower": "Jasmine",
"Yellow Flower": "Marigold"
}
},
"Fruits": {
"Yellow fruit": "Mango",
"Green fruit": "Guava",
"White Flower": "groovy"
},
"Trees": {
"label": {
"Yellow fruit": "Pumpkin",
"White Flower": "Bogan"
}
}
}
}
j = ExtendedDict(json)
print j.get('app.Garden.Flowers.White Flower'.split('.'))
вы получите:
Jasmine
Как и обычный get()
из dict, вы получаете None
, если указанный вами ключ (список) не существует нигде в дереве, и вы можете указать второй параметр как возвращаемое значение вместо None
Ответ 5
Я предлагаю вам использовать python-benedict
, подкласс python dict с полной поддержкой keypath и многими вспомогательными методами.
Вам просто нужно разыграть существующий дикт:
d = benedict(json)
# now your keys support dotted keypaths
print(d['app.Garden.Flower.White Flower'])
Вот библиотека и документация: https://github.com/fabiocaccamo/python-benedict