【问题标题】:In python, how best to insert key:value to json, given variable path and value在python中,如何最好地将key:value插入json,给定变量路径和值
【发布时间】:2019-03-27 07:10:35
【问题描述】:

我需要创建一个 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'}}]}

某些键可能已经存在,然后我只更新值。

数字键表示该键之前可以有多个值,我在数组的这个位置添加/更新值

【问题讨论】:

  • 您在哪里遇到无法发布整个代码并告诉我们解决的问题,请创建MCVE
  • @Kunal Mukherjee 感谢您的回复。在功能上,我不知道有什么问题,但是对于学习,作为 python 新手,我想知道这是否可以更优雅地编写,或者甚至更好,如果 Python 2.7 中已经包含了现有的模块函数,那确实一样的
  • 是否需要使用列表作为中间节点?插入空节点会使您的结构有点尴尬。字典实际上是一个稀疏数组。问题What is the best way to implement nested dictionaries 有一个很好的答案
  • @Mike Robins 感谢您的回复。输出 json 文件的要求是,如果例如 "a" 是数组类型的键,则 in 必须是 json 中的数组,例如 "a":[] ,即使它下面没有值。每个键都有预定义的类型,并且我收到的路径:值是相应构建的

标签: python json list dictionary


【解决方案1】:

这是我使用嵌套字典对您的数据结构的实现:

class Tree(dict):
    '''http://stackoverflow.com/questions/635483/what-is-the-best-way-to-implement-nested-dictionaries-in-python'''

    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'}}}}

但是您希望整数索引字典是数组。下面的例程逐步将嵌套字典转换为列表。它会进行一些复制,以免弄乱原始嵌套字典。我只会将其用作 outout 阶段的一部分。

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"
            }
        }
    ]
}

【讨论】:

    猜你喜欢
    • 2018-04-04
    • 2013-08-07
    • 1970-01-01
    • 2022-01-02
    • 2013-06-09
    • 2021-05-09
    • 1970-01-01
    • 2015-10-26
    • 2022-10-17
    相关资源
    最近更新 更多