Как превратить список Python в допустимый путь JSON? [Дубликат]

Если у вас есть доступ к изменению параметров JVM, добавление подробного вывода должно позволять вам видеть, какие классы загружаются из JAR.

java -verbose:class <other args>

Когда ваша программа запущена, JVM должна сбрасывать к стандартной информации, такой как:

...

[Загружено junit.framework.Assert из файла: / C: /Program%20Files/junit3.8.2/junit .jar]

...

94
задан martineau 17 November 2016 в 17:45
поделиться

11 ответов

Используйте reduce() для перемещения словаря:

from functools import reduce  # forward compatibility for Python 3
import operator

def getFromDict(dataDict, mapList):
    return reduce(operator.getitem, mapList, dataDict)

и повторного использования getFromDict, чтобы найти местоположение для сохранения значения для setInDict():

def setInDict(dataDict, mapList, value):
    getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value

Все, кроме последнего элемента в mapList, необходимы, чтобы найти «родительский» словарь, чтобы добавить значение, а затем использовать последний элемент, чтобы установить значение в правую клавишу.

Демо:

>>> getFromDict(dataDict, ["a", "r"])
1
>>> getFromDict(dataDict, ["b", "v", "y"])
2
>>> setInDict(dataDict, ["b", "v", "w"], 4)
>>> import pprint
>>> pprint.pprint(dataDict)
{'a': {'r': 1, 's': 2, 't': 3},
 'b': {'u': 1, 'v': {'w': 4, 'x': 1, 'y': 2, 'z': 3}, 'w': 3}}

Обратите внимание, что руководство по стилю Python PEP8 предписывает имена змеиных имен для функций . Вышеупомянутое работает одинаково хорошо для списков или комбинации словарей и списков, поэтому имена должны быть действительно get_by_path() и set_by_path():

from functools import reduce  # forward compatibility for Python 3
import operator

def get_by_path(root, items):
    """Access a nested object in root by item sequence."""
    return reduce(operator.getitem, items, root)

def set_by_path(root, items, value):
    """Set a value in a nested object in root by item sequence."""
    get_by_path(root, items[:-1])[items[-1]] = value
149
ответ дан Martijn Pieters 16 August 2018 в 00:28
поделиться
  • 1
    Насколько такое перемещение является надежным для произвольных вложенных структур? Будет ли он работать для смешанных словарей с вложенными списками? Как изменить getFromDict () для предоставления значения по умолчанию и присвоить значение по умолчанию default_value как None? Я новичок в Python с многолетней разработкой PHP и до разработки C. – Dmitriy Sintsov 11 February 2015 в 11:51
  • 2
    Также вложенный сопоставленный набор должен создавать несуществующие узлы, imo: списки для целых ключей, словари для строковых ключей. – Dmitriy Sintsov 11 February 2015 в 11:59
  • 3
    @ user1353510: как это бывает, здесь используется регулярный синтаксис индексирования, поэтому он также будет поддерживать списки внутри словарей. Просто передайте для них целые индексы. – Martijn Pieters♦ 11 February 2015 в 13:04
  • 4
    @ user1353510: разные способы использования требуют различного поведения. Код здесь не создает посредников, нет. – Martijn Pieters♦ 11 February 2015 в 13:04
  • 5
    @ user1353510: для значения по умолчанию используйте try:, except (KeyError, IndexError): return default_value вокруг текущей строки return. – Martijn Pieters♦ 11 February 2015 в 13:05

Как насчет проверки, а затем установить элемент dict без обработки всех индексов дважды?

Решение:

def nested_yield(nested, keys_list):
    """
    Get current nested data by send(None) method. Allows change it to Value by calling send(Value) next time
    :param nested: list or dict of lists or dicts
    :param keys_list: list of indexes/keys
    """
    last_key = keys_list.pop()
    for key in keys_list:
        nested = nested[key] #_dict.setdefault(key, {})
    while True:
        try:
            nested[last_key] = yield nested[last_key]
        except IndexError:
            print("no index {} in {}".format(last_key, nested))

Пример рабочего процесса:

ny = nested_yield(nested_dict, nested_address)
data_element = ny.send(None)
if data_element:
    # process element
    ...
else:
    # extend/update nested data
    ny.send(new_data_element)
    ...
ny.close()

Тест

>>> cfg= {'Options': [[1,[0]],[2,[4,[8,16]]],[3,[9]]]}
    ny = nested_yield(cfg, ['Options',1,1,1])
    ny.send(None)
[8, 16]
>>> ny.send('Hello!')
'Hello!'
>>> cfg
{'Options': [[1, [0]], [2, [4, 'Hello!']], [3, [9]]]}
>>> ny.close()
1
ответ дан Andrey 16 August 2018 в 00:28
поделиться

Чистый стиль Python без импорта:

def nested_set(element, value, *keys):
    if type(element) is not dict:
        raise AttributeError('nested_set() expects dict as first argument.')
    if len(keys) < 2:
        raise AttributeError('nested_set() expects at least three arguments, not enough given.')

    _keys = keys[:-1]
    _element = element
    for key in _keys:
        _element = _element[key]
    _element[keys[-1]] = value

example = {"foo": { "bar": { "baz": "ok" } } }
keys = ['foo', 'bar']
nested_set(example, "yay", *keys)
print(example)

Выход

{'foo': {'bar': 'yay'}}
0
ответ дан Arount 16 August 2018 в 00:28
поделиться

Использование сокращения является умным, но метод set OP может иметь проблемы, если родительские ключи не существуют во вложенном словаре. Поскольку это первая публикация SO, которую я видел для этого объекта в моем поиске в Google, я хотел бы немного улучшить его.

Метод set in ( Установка значения во вложенном словаре python список индексов и значение ) кажется более надежным для отсутствующих родительских ключей. Чтобы скопировать его:

def nested_set(dic, keys, value):
    for key in keys[:-1]:
        dic = dic.setdefault(key, {})
    dic[keys[-1]] = value

Кроме того, может быть удобно иметь метод, который обходит дерево ключей и получает все пути абсолютного ключа, для которых я создал:

def keysInDict(dataDict, parent=[]):
    if not isinstance(dataDict, dict):
        return [tuple(parent)]
    else:
        return reduce(list.__add__, 
            [keysInDict(v,parent+[k]) for k,v in dataDict.items()], [])

Одно из них - преобразовать вложенное дерево в pandas DataFrame, используя следующий код (при условии, что все листы во вложенном словаре имеют одинаковую глубину).

def dict_to_df(dataDict):
    ret = []
    for k in keysInDict(dataDict):
        v = np.array( getFromDict(dataDict, k), )
        v = pd.DataFrame(v)
        v.columns = pd.MultiIndex.from_product(list(k) + [v.columns])
        ret.append(v)
    return reduce(pd.DataFrame.join, ret)
9
ответ дан Community 16 August 2018 в 00:28
поделиться
  1. Принятое решение не будет работать непосредственно для python3 - ему понадобится from functools import reduce.
  2. Также кажется, что более pythonic использует цикл for. См. Цитату из Что нового в Python 3.0 . Удалено reduce(). Используйте functools.reduce(), если вам это действительно нужно; однако в 99% случаев явная for петля более читаема.
  3. Затем принятое решение не устанавливает несуществующие вложенные ключи (возвращает KeyError) - см. ответ @ eafit для решения

Итак, почему не используйте предложенный метод из вопроса kolergy для получения значения:

def getFromDict(dataDict, mapList):    
    for k in mapList: dataDict = dataDict[k]
    return dataDict

И код из ответа @ eafit для установки значения:

def nested_set(dic, keys, value):
    for key in keys[:-1]:
        dic = dic.setdefault(key, {})
    dic[keys[-1]] = value

Оба работают прямо в python 2 и 3

25
ответ дан DomTomCat 16 August 2018 в 00:28
поделиться
  • 1
    Я предпочитаю это решение, но будьте осторожны. Если я не ошибаюсь, поскольку словари Python не являются неизменными, getFromDict имеет потенциал для уничтожения dataDict вызывающего. Сначала я хотел бы copy.deepcopy(dataDict). Конечно, (как написано) это поведение желательно во второй функции. – Dylan F 13 June 2018 в 03:33

Если вы также хотите работать с произвольным json, включая вложенные списки и dicts, и хорошо обрабатывать недопустимые пути поиска, вот мое решение:

from functools import reduce


def get_furthest(s, path):
    '''
    Gets the furthest value along a given key path in a subscriptable structure.

    subscriptable, list -> any
    :param s: the subscriptable structure to examine
    :param path: the lookup path to follow
    :return: a tuple of the value at the furthest valid key, and whether the full path is valid
    '''

    def step_key(acc, key):
        s = acc[0]
        if isinstance(s, str):
            return (s, False)
        try:
            return (s[key], acc[1])
        except LookupError:
            return (s, False)

    return reduce(step_key, path, (s, True))


def get_val(s, path):
    val, successful = get_furthest(s, path)
    if successful:
        return val
    else:
        raise LookupError('Invalid lookup path: {}'.format(path))


def set_val(s, path, value):
    get_val(s, path[:-1])[path[-1]] = value
0
ответ дан Grant Palmer 16 August 2018 в 00:28
поделиться

Эта библиотека может быть полезна: https://github.com/akesterson/dpath-python

Библиотека python для доступа и поиска словарей через / slashed / paths ala xpath

В принципе, он позволяет вам глотать словарь, как если бы он был файловой системой.

8
ответ дан jonrsharpe 16 August 2018 в 00:28
поделиться

Вместо того, чтобы каждый раз, когда вы хотите посмотреть значение, вы получаете удар производительности, как насчет того, чтобы вы сплели словарь, а затем просто найдите ключ, например b:v:y

def flatten(mydict):
  new_dict = {}
  for key,value in mydict.items():
    if type(value) == dict:
      _dict = {':'.join([key, _key]):_value for _key, _value in flatten(value).items()}
      new_dict.update(_dict)
    else:
      new_dict[key]=value
  return new_dict

dataDict = {
"a":{
    "r": 1,
    "s": 2,
    "t": 3
    },
"b":{
    "u": 1,
    "v": {
        "x": 1,
        "y": 2,
        "z": 3
    },
    "w": 3
    }
}    

flat_dict = flatten(dataDict)
print flat_dict
{'b:w': 3, 'b:u': 1, 'b:v:y': 2, 'b:v:x': 1, 'b:v:z': 3, 'a:r': 1, 'a:s': 2, 'a:t': 3}

. Таким образом, вы можете просто просмотрите элементы, используя flat_dict['b:v:y'], которые дадут вам 1.

И вместо того, чтобы перемещаться по словарю при каждом поиске, вы можете ускорить это, сглаживая словарь и сохраняя вывод так, чтобы что поиск с холодного старта означал бы загрузку сплющенного словаря и просто выполнение поиска ключа / значения без обхода.

1
ответ дан OkezieE 16 August 2018 в 00:28
поделиться

Решено это с рекурсией:

def get(d,l):
    if len(l)==1: return d[l[0]]
    return get(d[l[0]],l[1:])

Используя ваш пример:

dataDict = {
    "a":{
        "r": 1,
        "s": 2,
        "t": 3
        },
    "b":{
        "u": 1,
        "v": {
            "x": 1,
            "y": 2,
            "z": 3
        },
        "w": 3
        }
}
maplist1 = ["a", "r"]
maplist2 = ["b", "v", "y"]
print(get(dataDict, maplist1)) # 1
print(get(dataDict, maplist2)) # 2
0
ответ дан Poh Zi How 16 August 2018 в 00:28
поделиться

Альтернативный способ, если вы не хотите поднимать ошибки, если один из ключей отсутствует (чтобы ваш основной код мог работать без прерывания):

def get_value(self,your_dict,*keys):
    curr_dict_ = your_dict
    for k in keys:
        v = curr_dict.get(k,None)
        if v is None:
            break
        if isinstance(v,dict):
            curr_dict = v
    return v

В этом случае, если есть входных ключей нет, возвращается None, которое может использоваться как проверка вашего основного кода для выполнения альтернативной задачи.

1
ответ дан Pulkit 16 August 2018 в 00:28
поделиться

Как насчет использования рекурсивных функций?

Чтобы получить значение:

def getFromDict(dataDict, maplist):
    first, rest = maplist[0], maplist[1:]

    if rest: 
        # if `rest` is not empty, run the function recursively
        return getFromDict(dataDict[first], rest)
    else:
        return dataDict[first]

И установить значение:

def setInDict(dataDict, maplist, value):
    first, rest = maplist[0], maplist[1:]

    if rest:
        try:
            if not isinstance(dataDict[first], dict):
                # if the key is not a dict, then make it a dict
                dataDict[first] = {}
        except KeyError:
            # if key doesn't exist, create one
            dataDict[first] = {}

        setInDict(dataDict[first], rest, value)
    else:
        dataDict[first] = value
1
ответ дан xyres 16 August 2018 в 00:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: