【问题标题】:In Python, how to generate nested dict from dotted json file?在 Python 中,如何从点分 json 文件生成嵌套字典?
【发布时间】:2020-03-04 18:29:17
【问题描述】:

我有一个像这样的 json 文件:

{
    "a": 0.7615894039735099,
    "a.b": 0.7152317880794702,
    "a.c": 0.026490066225165563
    "a.b.d": 0.0001

     "f": 0.002
     "f.g": 0.00003

     "h.p.q": 0.0004
}

说整个字典被称为“root”

我想这样使用它

if "c" in root["a"] and if root["a"]["c"] > 0.0002:
   print("something")

有人可以帮忙吗? 非常感谢!

【问题讨论】:

  • 普通python字典的数据结构不能支持你的用例。由于您将float 存储在root["a"] 中,因此在执行"c" in root["a"] 语句时它将返回TypeError,因为float 类型不可迭代。
  • 我认为,首先您需要重新构造 JSON 数据以使其嵌套。
  • 如果你能以任何方式将'a'和'c'键存储在一个数组中你可以使用这个root['.'.join(['a','c'])]

标签: python json dictionary


【解决方案1】:

由于键是散列的 - 字符串键中是否存在点没有语义意义,并​​且尝试访问 root["a"]["c"] 将导致 TypeError 异常,如前所述。 但是,您可以重新构建字典以具有您正在寻找的嵌套结构。 代码大致如下:

root = {
    "a": 0.7615894039735099,
    "a.b": 0.7152317880794702,
    "a.c": 0.026490066225165563,
    "a.b.d": 0.0001,
    "f": 0.002,
    "f.g": 0.00003,
    "h.p.q": 0.0004
}

result = {}
for key, value in root.items():
     if not isinstance(key, str):
         result[key] = value
     is_nested = "." in key
     nesting_clash = any([k.startswith(key) for k in root if k != key])
     if nesting_clash:
         print(f"key {key} has nesting clash ; replacing with {key}._v")
         # continue # fixed after comment
         key = f"{key}._v"
         is_nested = True
     if not is_nested:
         result[key] = value
     key_parts = key.split(".")
     tmp = result
     for idx, key_part in enumerate(key_parts):
         default_value = {} if idx < len(key_parts) - 1 else value
         tmp[key_part] = tmp.get(key_part, default_value)
         tmp = tmp[key_part]

注意:您必须丢弃发生冲突的键(例如 "a""a.b")或为它们创建默认行为。在我的示例中,我决定丢弃它们。

编辑:我已经用 ._v 的键替换替换了跳过。这样,您可以保留所有值并使用以下函数重建原始字典/JSON:

def unnest_dict(d, sep="."):
    result = {}
    for key, val in d.items():
        if not isinstance(val, dict):
            result[key] = val
            continue
        if "_v" in val:
            result[key] = val.pop("_v")
        unnested_val = unnest_dict(val, sep)
        for k, v in unnested_val.items():
            result[sep.join([key, k])] = v
    return result

【讨论】:

  • 感谢 A.Rom。但对我来说,我必须有 root["a"] 才能返回属性值。所以我想我这种情况只能使用类对象来创建树吧?
  • 您能否更具体地了解如何重建原始嵌套字典?如果可行,我可以尝试这种方式。@A。罗
  • @shenmufeng - 已编辑并允许保留原始值 + 重建原始字典的函数。
  • 很好的解决方案!谢谢你,罗姆。我会接受你的建议,非常感谢你的帮助。
【解决方案2】:

看下面的sn-p。


def merge(a, b, path=None):
    '''merges b into a'''
    if path is None: path = []
    for key in b:
        if key in a:
            if isinstance(a[key], dict) and isinstance(b[key], dict):
                merge(a[key], b[key], path + [str(key)])
            elif a[key] == b[key]:
                pass # same leaf value
            else:
                raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
        else:
            a[key] = b[key]
    return a


def convert_dotted_json(dottedJson):
    '''
    parameter
        dottedJson : dict type
    '''
    root = {}

    for key in dottedJson:
        split_key = key.split(".");
        split_key.reverse()
        value = dottedJson [key]
        curr = {split_key[0]: value};
        for ind in range(1, len(split_key)):
            curr = {split_key[ind]:curr}
        root = merge(root, curr)

    return root


test = {
    "a.b.c" : 0.026490066225165563,
    "a.b.d" : 0.0001,
    "f.g": 0.00003,
    "f.h": 0.00003,
    "h.p.q": 0.0004
}

# print(convert_dotted_json(test))

Andrew Cook's 的答案复制merge function

【讨论】:

  • 谢谢维韦克。但我确实需要使用 root["a"] 的值。看来我们无法实现这个目标?@Vivek Kundariya
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 2019-06-16
  • 2019-05-09
  • 2021-09-27
  • 2018-05-31
  • 2017-12-12
  • 1970-01-01
相关资源
最近更新 更多