В Python, как лучше всего вставить ключ: значение в JSON, учитывая путь переменной и значение - PullRequest
1 голос
/ 27 марта 2019

Мне нужно создать файл json, учитывая словарь путей и их значений. Я написал некоторый код для добавления записи, которая выглядит так, как будто она функционирует, и результат верен, но как кто-то, кто новичок в python, я задаюсь вопросом, как это можно улучшить, и если есть функция, которая делает то же самое, уже существует в модулях входит в состав Python 2.7?

   def path_to_list(path):
        if isinstance(path, (str,)):
            map_list = path.split("/")
            for i, key in enumerate(map_list):
                if key.isdigit():
                    map_list[i] = int(key)
        else:
            map_list = path
        return map_list


def add_to_dictionary(dic, keys, value):
    for i, key in enumerate(keys[:-1]):
        if i < len(keys)-1 and isinstance(keys[i+1], int):
            # Case where current key should be a list, since next key is
            # is list position
            if key not in dic.keys():
                # Case list not yet exist
                dic[keys[i]] = []
                dic[keys[i]].append({})
                dic = dic.setdefault(key, {})
            elif not isinstance(dic[key], list):
                # Case key exist , but not a list
                # TO DO : check how to handle
                print "Failed to insert " + str(keys) + ", trying to insert multiple to not multiple  "
                break
            else:
                # Case where the list exist
                dic = dic.setdefault(key, {})
        elif i < len(keys)-1 and isinstance(key, int):
            # Case where current key is instance number in a list
            try:
                # If this succeeds instance already exist
                dic = dic[key]
            except (IndexError,KeyError):
                # Case where list exist , but need to add new instances  ,
                # as key instance  not exist
                while len(dic)-1 < key:
                    dic.append({})
                dic = dic[key]
        else:
            # Case where key is not list or instance of list
            dic = dic.setdefault(key, {})
    # Update value
    dic[keys[-1]] = value

my_dict1 ={}
add_to_dictionary(my_dict1, path_to_list("a/0/b/c"), 1)
print my_dict1

{'a': [{'b': {'c': 1}}]}

add_to_dictionary(my_dict1, path_to_list("a/2/b/c"), "string")
print my_dict1

{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'string'}}]}

add_to_dictionary(my_dict1, path_to_list("a/2/b/c"), "new string")
print my_dict1

{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'new string'}}]}

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

Цифровые ключи указывают, что ключ, прежде чем он может иметь несколько значений, и я добавляю / обновляю значение в этом месте в массиве

1 Ответ

0 голосов
/ 01 апреля 2019

Вот моя реализация вашей структуры данных с использованием вложенных словарей:

class Tree(dict):
    '''/525385/kakov-nailuchshii-sposob-realizatsii-vlozhennyh-slovarei'''

    def __missing__(d, k):
        v = d[k] = type(d)()
        return v

    def grow(d, path, v):
        ps = map(lambda k: int(k) if k.isdigit() else k, path.split('/'))
        reduce(lambda d, k: d[k], ps[:-1], d)[ps[-1]] = v

Проверка этого:

t = Tree()
t.grow('a/0/b/c', 1)
print t
t['a'][2]['b']['c'] = 'string'
print t
t.grow('a/2/b/c', 'new_string')
print t

дает:

{'a': {0: {'b': {'c': 1}}}}
{'a': {0: {'b': {'c': 1}}, 2: {'b': {'c': 'string'}}}}
{'a': {0: {'b': {'c': 1}}, 2: {'b': {'c': 'new_string'}}}}

Но вы хотите, чтобы целочисленные словари были массивами. Подпрограмма ниже проходит через вложенные словари, превращая некоторые из них в списки. Это делает некоторое копирование, чтобы не испортить оригинальные вложенные словари. Я бы использовал это как часть аутсайдера.

import numbers
def keys_all_int(d):
    return reduce(lambda r, k: r and isinstance(k, numbers.Integral), d.keys(), True)

def listify(d):
    '''
    Take a tree of nested dictionaries, and
    return a copy of the tree with sparse lists in place of the dictionaries
    that had only integers as keys.
    '''
    if isinstance(d, dict):
        d = d.copy()
        for k in d:
            d[k] = listify(d[k])
        if keys_all_int(d):
            ds = [{}]*(max(d.keys())+1)
            for k in d:
                ds[k] = d[k]
            return ds
    return d

Проверка этого:

t = Tree()
t.grow('a/0/b/c', 1)
print listify(t)
t['a'][2]['b']['c'] = 'string'
print listify(t)
t.grow('a/2/b/c', 'new_string')
print listify(t)

Дает:

{'a': [{'b': {'c': 1}}]}
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'string'}}]}
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'new_string'}}]}

Наконец, если вы имеете дело с JSON, используйте модуль json:

import json
print json.dumps(listify(t),
    sort_keys=True, indent = 4, separators = (',', ': '))

Дает:

{
    "a": [
        {
            "b": {
                "c": 1
            }
        },
        {},
        {
            "b": {
                "c": "new_string"
            }
        }
    ]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...