如何创建嵌套的字典键并从命名空间键值对列表中为其分配值?

时间:2020-04-19 22:10:43

标签: python dictionary recursion key-value

我的env var看起来像这样:

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

但是我不确定如何遍历字符串,分割为“-”并构建字典。

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

我怀疑这是递归工作,我现在才确定确切地实现它

3 个答案:

答案 0 :(得分: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_in here的实现。一个更简单的替代方法可能是

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

这使用.setdefault()方法获取嵌套的字典,如果尚不存在,则会添加一个新字典。

答案 1 :(得分:2)

您可以这样做:

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对应的值,否则创建一个新字典。

答案 2 :(得分:1)

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

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的灵感)

然后,您可以使用dict迭代拆分值:

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