从元组列表创建嵌套字典

时间:2021-05-26 13:55:14

标签: python json dictionary recursion formatting

给定一个包含元组的名为 outlines 的列表:(level, title),创建一个嵌套字典,其深度基于级别,键值基于标题。

示例列表:
[(1, 摘要)
(二、背景)
(二、方法)
(2, 结果)
(3、统计)
(3, 图片)
(一、简介)]

这应该输出:

{
"Abstract": {
    "Background": {}, 
    "Methods": {}, 
    "Results": {
        "Statistics": {},
        "Images": {}
    }
},
"Introduction": {}
}

到目前为止,我已经尝试了递归解决方案,但到目前为止导致了无法追踪的错误行为。这是迄今为止我提出的最佳解决方案,但由于预定义的 for 循环,我无法防止不同级别的重复:

def structure(outlines, current_level=1, previous_title=''):
    section = dict()
    for i, (level, title) in enumerate(outlines):
        if level == current_level:
            section[title] = {}
            previous_title = title
        elif level > current_level:
            section[previous_title] = structure(outlines[i:], level)
        elif level < current_level:
            pass # Unknown
    return section

有什么建议吗?

3 个答案:

答案 0 :(得分:0)

假设顺序很重要,那么这将起作用:

generator = [
    (1, 'Abstract'),
    (2, 'Background'),
    (2, 'Methods'),
    (2, 'Results'),
    (3, 'Statistics'),
    (3, 'Images'),
    (1, 'Introduction')
]

# keep track of latest place in the dict
current_tree = []

# dict that you want to generate
d = {}

for i, value in generator:

    # if this, then you are at the highest level
    # so just add your value at the top
    if current_tree==[] or i==1:
        d[value] = {}
        current_tree = [value]

    # otherwise go back in the tree and add your value
    else:

        tmp_d = d
        for key in current_tree[:i-1]:
            tmp_d = tmp_d[key]

        tmp_d[value] = {}

        current_tree = current_tree[:i] + [value]

返回:

{'Abstract': {'Background': {'Images': {}, 'Statistics': {}},
              'Methods': {},
              'Results': {}},
 'Introduction': {}}

答案 1 :(得分:0)

这是我的递归解决方案:

import json
inlist = [
    (1, "Abstract"),
    (2, "Background"),
    (2, "Methods"),
    (2, "Results"),
    (3, "Statistics"),
    (3, "Images"),
    (1, "Introduction"),
]

out = dict()
# IMPORTANT: Dictionaries are ordered in Python 3.6 (under the CPython implementation at least) unlike in previous incarnations.
def addElem(dest_level, new_elem, current_container, current_level=1):
    # list(current_container.keys())[-1] gets the most recently added element at the current level.
    if (current_level < dest_level):
        addElem(dest_level, new_elem, current_container[list(current_container.keys())[-1]], current_level+1)
    else:
        current_container[new_elem] = dict()

for el in inlist:
    addElem(el[0], el[1], out)

print(json.dumps(out, indent=2))

输出:

{
  "Abstract": {
    "Background": {},
    "Methods": {},
    "Results": {
      "Statistics": {},
      "Images": {}
    }
  },
  "Introduction": {}
}

答案 2 :(得分:0)

感谢 John R. Paul,我们已经有了一个可行的解决方案,但我想要一个不依赖于订购字典的解决方案。作为额外的好处,该解决方案是非递归的(尽管 John R. Paul 的解决方案是尾递归的,因此可以简单地重写为使用 while 循环)。

def add_all(generator_of_pairs):
    stack = [{}]
    for (level, name) in generator_of_pairs:
        del stack[level:]
        new_dict = {}
        stack[level - 1][name] = new_dict
        stack.append(new_dict)
    return stack[0]

请注意,此解决方案假设从 1 个元素到下一个元素的嵌套级别增加不能超过 1 - 但希望这个假设显然是必要的。