【问题标题】:Python: Turn List of Tuples into Dictionary of Nested DictionariesPython:将元组列表转换为嵌套字典的字典
【发布时间】:2017-01-20 07:59:07
【问题描述】:

所以我手头有点问题。我有一个元组列表(由级别编号和消息组成),最终将成为 HTML 列表。我的问题是,在这种情况发生之前,我想将元组值转换为嵌套字典的字典。所以这里是例子:

# I have this list of tuples in format of (level_number, message)
tuple_list = [(1, 'line 1'), (2, 'line 2'), (3, 'line 3'), (1, 'line 4')]

# And I want to turn it into this
a_dict = {
    'line 1': {
        'line 2': {
            'line 3': {}
        }
    }, 
    'line 4': {}
}

任何帮助都将不胜感激,只要它是有效的 Python 3。谢谢!

【问题讨论】:

  • 我假设您的意思是按 level_number 的结果字典中的深度?所以元组的第一个元素为 1 意味着它在字典的根级别。但是,“更深层次”嵌套在“第 1 行”而不是“第 4 行”中的信息从何而来?对不起,如果我没有在这里识别模式
  • 第 1 行、第 2 行和第 3 行之间可以分组的关系是什么?例如它们可以被视为对象并相互关联吗?
  • 我想明确一点,您遇到问题的原因是您的数据结构。如果您对此数据有任何控制权,请更改您的数据结构,而不是在这里实施任何解决方案。如果您无法控制数据,则可以将其视为一棵树。构建一个跟踪其父母和孩子的class TreeNode 可能更明智。
  • 对@Minato,是的,level_number 可以被认为是深度。深度与嵌套有关。字符串与排序无关。因此,如果一个值的深度为 3,它将嵌套在其之前深度为 2 的最近的值之下。
  • 对于@AdamSmith,这与 Markdown 处理项目有关,所以不,我对给出的信息的控制权为零。如果您愿意提出一个示例来说明“TreeNode”的含义,那就太好了。

标签: python list python-3.x dictionary tuples


【解决方案1】:

假设您只有三个级别,如下所示:

tuple_list = [(1, 'line 1'), (2, 'line 2'), (3, 'line 3'), (1, 'line 4')]

a_dict = {}

for prio, key in tuple_list:
    if prio == 1:
        a_dict[key] = {}
        first_level = key
    if prio == 2:
        a_dict[first_level][key] = {}
        second_level = key
    if prio == 3:
        a_dict[first_level][second_level][key] = {}
    # So on ...
print a_dict

这也假设层次结构是按顺序列出的,这意味着 level 1, level 1', level 2, level 3 将是 level 1 的单个 dict,以及 level 1' -> level 2 -> level 这样的层次结构顺序3. 所以下面

tuple_list = [(1, 'line 5'), (1, 'line 1'), (2, 'line 2'), (3, 'line 3'), (1, 'line 4')]

会产生以下结果:

{'line 1': {'line 2': {'line 3': {}}}, 'line 4': {}, 'line 5': {}}

或者更复杂一点:

tuple_list = [(1, 'line 1'), (2, 'line 2'), (2, 'line 6'), (3, 'line 3'), (3, 'line 7'), (1, 'line 4'), (1, 'line 5')]

会产生

{'line 1': {'line 2': {}, 'line 6': {'line 3': {}, 'line 7': {}}}, 'line 4': {}, 'line 5': {}}

由于您的级别不限于少数,仅通过简单的 IF 来做到这一点并不是一个好方法。最好先构造一棵树,然后遍历树,创建你想要的表示。这样做也很容易,您有几个根节点(其中 parent=None),每个节点都有一个子节点列表,并且对子节点重复此操作,因此您有一棵树。您现在从根开始并进行您想要的排序!

它很容易实现,我想你明白了!

【讨论】:

  • 你对“更复杂”的例子有正确的想法,但是如果函数可以深入 5 层,我会更高兴。
  • @tedm1106 它实际上与我提供的完全相同。带有四个 if 的代码不会那么漂亮,但您明白了这个想法,并且可能可以改进它以使其在没有 if 的情况下工作。
  • 对不起,这很明显可以扩展:P
  • 这还不错,但有可能打破像[(1, "foo"), (2, "bar"), (1, "spam"), (3, "eggs")] 这样的非标准(但可能有效!)级别。我不确定从 1 -> 3 跳转的“正确”解释是什么(我只是忽略它并将“3”视为“2”),但它并没有引发KeyError
  • 您的答案处理它的方式@AdamSmith 非常好。谢谢。
【解决方案2】:

正如我在评论中指出的那样,如果您对传入的数据结构有任何控制权,那么您应该强烈考虑更改传入的数据结构。元组的顺序列表绝对不适合您在这里所做的事情。但是,如果你把它当作一棵树,它是可能的。让我们构建一个(健全的)数据结构来解析它

class Node(object):
    def __init__(self, name, level, parent=None):
        self.children = []
        self.name = name
        self.level = level
        self.parent = parent

    def make_child(self, othername, otherlevel):
        other = self.__class__(othername, otherlevel, self)
        self.children.append(other)
        return other

现在您应该能够以某种合理的方式迭代您的数据结构

def make_nodes(tuple_list):
    """Builds an ordered grouping of Nodes out of a list of tuples
    of the form (level, name). Returns the last Node.
    """

    curnode = Node("root", level=-float('inf'))
    # base Node who should always be first.

    for level, name in tuple_list:
        while curnode.level >= level:
            curnode = curnode.parent
            # if we've done anything but gone up levels, go
            # back up the tree to the first parent who can own this
        curnode = curnode.make_child(name, level)
        # then make the node and move the cursor to it
    return curnode

结构完成后,您可以对其进行迭代。如果您采用深度优先或广度优先,这无关紧要,所以让我们做一个 DFS 只是为了便于实施。

def parse_tree(any_node):
    """Given any node in a singly-rooted tree, returns a dictionary
    of the form requested in the question
    """

    def _parse_subtree(basenode):
        """Actually does the parsing, starting with the node given
        as its root.
        """

        if not basenode.children:
            # base case, if there are no children then return an empty dict
            return {}
        subresult = {}
        for child in basenode.children:
            subresult.update({child.name: _parse_subtree(child)})
        return subresult

    cursor = any_node
    while cursor.parent:
        cursor = cursor.parent
        # finds the root node
    result = {}
    for child in cursor.children:
        result[child.name] = _parse_subtree(child)
    return result

然后输入你的元组列表et voila

tuple_list = [(1, 'line 1'), (2, 'line 2'), (3, 'line 3'), (1, 'line 4')]

last_node = make_nodes(tuple_list)
result = parse_tree(last_node)
# {'line 1': {'line 2': {'line 3': {}}}, 'line 4': {}}

【讨论】:

  • 很高兴我能帮上忙。真是浪费了午休时间;)
猜你喜欢
  • 1970-01-01
  • 2012-09-06
  • 2019-12-28
  • 1970-01-01
  • 2022-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多