【问题标题】:How can I construct a nested dictionary?如何构建嵌套字典?
【发布时间】:2017-11-25 17:50:21
【问题描述】:

我有一个字符串列表,我必须从中构造一个字典。所以,例如,我有:

foo.bar:10
foo.hello.world:30
xyz.abc:40
pqr:100

这表示为一个字典:

{
  "foo": {
    "bar": 10,
    "hello": {
      "world": 30
    }
  },
  "xyz": {
    "abc": 40
  },
  "pqr": 100
}

This question 基于相同的前提,但答案讨论了硬编码的深度,例如:

mydict = ...
mydict['foo']['bar'] = 30

由于左侧的点分隔字符串可能有任何深度,我无法找到构建字典的方法。我应该如何解析点分隔字符串并构建字典?

【问题讨论】:

标签: python python-3.x dictionary


【解决方案1】:

基于链接中的解决方案,您可以

  1. 遍历每一行
  2. 为每一行提取一个键列表及其值
  3. 使用setdefault 将每个键递归到字典中
  4. 在底部赋值

lines = \
'''
foo.bar:10
foo.hello.world:30
xyz.abc:40
pqr:100
'''.splitlines()

d = {}

for l in lines:
    k, v = l.split(':')
    *f, l = k.split('.')

    t = d
    for k in f:
        t = t.setdefault(k, {})
    t[l] = int(v)   # don't perform a conversion if your values aren't numeric
print(d)
{
    "pqr": 100,
    "foo": {
        "bar": 10,
        "hello": {
            "world": 30
        }
    },
    "xyz": {
        "abc": 40
    }
}

递归setdefault遍历从here学习。


分解每一步-

  1. 拆分:,提取key-list字符串和值

    k, v = l.split(':')
    
  2. 拆分. 上的密钥字符串以获取密钥列表。我也借此机会对密钥进行了分区,因此我单独引用了最后一个密钥,该密钥将成为v 的密钥。

    *f, l = k.split('.')
    

    *f 是包罗万象的赋值,f 是任意数量值的列表(如果键字符串中只有一个键,则可能是 0 个值!)

  3. 对于密钥列表f 中的每个密钥k,使用setdefault 向下递归到“树”。这类似于递归遍历链表。

    for k in f:
        t = t.setdefault(k, {})
    
  4. 最后,最后一个键值对来自lv

    t[l] = v
    

【讨论】:

  • 喜欢你的解决方案,但不喜欢你的命名:D
  • @user1767754 哈哈,很抱歉。这是一个社区 wiki,因此请随时修改。我不想从这个答案中获得任何代表,因为它大部分是链接的衍生品,但不足以回答这个问题。
  • 哦,不……我不担心,只是我的命名习惯过于表达了。
【解决方案2】:

增量构建有什么问题?

mydict = {}
mydict["foo"] = {}
mydict["foo"]["bar"] = 30
mydict["foo"]["hello"] = {}
mydict["foo"]["hello"]["world"] = 30
mydict["foo"]["xyz"] = {}
mydict["foo"]["xyz"]["abc"] = 40
mydict["foo"]["pqr"] = 100
# ...
pprint.pprint(mydict) # {'foo': {'bar': 30, 'hello': {'world': 30}, 'pqr': 100, 'xyz': {'abc': 40}}}

包括解析,你可以这样使用:

import pprint

inp = """foo.bar:10
foo.hello.world:30
xyz.abc:40
pqr:100
"""

mydict = {}

for line in inp.splitlines():
    s, v = line.split(':')
    parts = s.split(".")
    d = mydict
    for i in parts[:-1]:
        if i not in d:
            d[i] = {}
        d = d[i]
    d[parts[-1]] = v

pprint.pprint(mydict) # {'foo': {'bar': '10', 'hello': {'world': 30'}}, 'pqr': '100', 'xyz': {'abc': '40'}}

【讨论】:

  • 我必须解析字符串的点分隔部分并构造字典。手动构建它需要硬编码,这不是一种选择。
  • @user2064000:查看我的更新。解析时以增量方式构建字典的工作方式完全相同。
【解决方案3】:

在您的情况下要考虑的一个关键点是,您要么想在父字典的值部分 or 一个整数中创建字典

x = """
foo.bar:10
foo.hello.world:30
xyz.abc:40
pqr.a:100
"""

tree = {}

for item in x.split():
    level, value = item.split(":")[0], item.split(":")[1]

    t = tree
    for part in item.split('.'):
        keyval = part.split(":")
        if len(keyval) > 1:
            #integer
            t = t.setdefault(keyval[0], keyval[1])
        else:
            t = t.setdefault(part, {})


import pprint
pprint.pprint(tree)

结果:

{'foo': {'bar': '10', 'hello': {'world': '30'}},
 'pqr': {'a': '100'},
 'xyz': {'abc': '40'}}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 2019-12-08
    相关资源
    最近更新 更多