【问题标题】:how can I create nested dictionary keys and assign them values from a list of namespaced key value pairs?如何创建嵌套字典键并从命名空间键值对列表中为其分配值?
【发布时间】:2020-08-02 08:33:34
【问题描述】:

我的环境变量看起来像这样:

CONFIG-SOMEKEY-SOMEOTHERKEY = val345
CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678
CONFIG-ANOTHERKEY = val222

我想用它们创建一个字典,看起来像:

{
  'SOMEKEY': {
    'SOMEOTHERKEY': 'val3242',
    'SOMEOTHEROTHERKEY': 'val678'
  }
  'ANOTHERKEY': 'val222'
}

“CONFIG-”是一个前缀,表示应该使用哪些变量 - 所以我可以像这样轻松过滤它们:

config_fields = [i for i in os.environ if i.startswith("CONFIG-")]

但我不确定如何遍历字符串,在“-”上拆分并构建一个字典。

循环时我在想我可以检查它是否是最后一项并分配值,但它如何知道它所在键的完整路径?

我怀疑这是一项递归工作,我现在才确切知道如何实现它

【问题讨论】:

  • 谢谢,打错了,改正了

标签: python dictionary recursion key-value


【解决方案1】:

你可以这样做:

data = ['CONFIG-SOMEKEY-SOMEOTHERKEY = val345',
        'CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678',
        'CONFIG-ANOTHERKEY = val222']

result = {}
for e in data:
    key, value = e.split(" = ")  # split into key and value
    path = key.split("-")  # split the key into parts
    ref = result
    for part in path[1:-1]:
        ref[part] = part in ref and ref[part] or {}
        ref = ref[part]
    ref[path[-1]] = value  # take the last part of key and set the value

print(result)

输出

{'SOMEKEY': {'SOMEOTHERKEY': 'val345', 'SOMEOTHEROTHERKEY': 'val678'}, 'ANOTHERKEY': 'val222'}

这部分:

ref = result
for part in path[1:-1]:
    ref[part] = part in ref and ref[part] or {}
    ref = ref[part]
ref[path[-1]] = value

会创建嵌套字典,相当于:

for part in path[1:-1]:
    if part not in ref:
        ref[part] = {}
    ref = ref[part]

因此,如果 part 在字典中,则将 ref 设置为与 part 对应的值,否则创建一个新字典。

【讨论】:

  • CONFIG-SOMEKEY-SOMEOTHERKEY = val345 不是字符串,尽管 CONFIG-SOMEKEY-SOMEOTHERKEY env var 的值为 val345
  • 对不起,我不明白你的意思?这与您的问题所需的输出有何不同?
  • 你可以在这里使用setdefault()吗?
  • @NomadMonad 我可以,但每次调用 setdefault 都会创建一个字典对象,这样表达式就会短路并且不会创建不必要的对象。
  • 您能否进一步介绍在您的答案中创建嵌套 dict 的 sn-p?我仍在尝试完全了解它是如何工作的
【解决方案2】:

您可以使用toolz 中的assoc_in 函数。拆分-上的名称并切掉前缀。

import os

from toolz.dictoolz import assoc_in

CONFIG={}

for k, v in os.environ.items():
    if k.startswith("CONFIG-"):
        assoc_in(CONFIG, k.split('-')[1:], v)

如果不想添加依赖,可以看assoc_inhere的实现。一个更简单的替代品可能类似于

def assoc_in(d, ks, v):
    for k in ks[:-1]:
        d = d.setdefault(k, {})
    d[ks[-1]] = v

这使用.setdefault() 方法来获取嵌套的dicts,如果它还不存在,它将添加一个新的。

【讨论】:

    【解决方案3】:

    您可以像这样获取环境变量:

    import os
    
    text = [f"{k} = {v}" for k,v in os.environ.items() if k.startswith("CONFIG-")]
    print(env)
    

    (灵感来自How to access environment variable values? - 尤其是这个answer

    然后您可以使用 dicts 迭代地拆分您的值:

    text = """CONFIG-SOMEKEY-SOMEOTHERKEY = val345
    CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678
    CONFIG-ANOTHERKEY = val222"""
    
    text = text.split("\n")
    
    d = {}
    
    curr_d = d
    for part in text:
        while "-" in part:
            a, b = part.split("-",1)
            if '-' in b:
                curr_d [a] = curr_d.get(a,{})
                curr_d = curr_d[a]
            part = b
        a, b = part.split("=",1)
        curr_d[a] = b
    
        curr_d = d
    
    print(d)
    

    输出:

    {'CONFIG': {'SOMEOTHERKEY ': ' val345', 
                'SOMEOTHEROTHERKEY ': ' val678'}, 
     'ANOTHERKEY ': ' val222'}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      相关资源
      最近更新 更多