Python:从父子值列表创建嵌套字典

Posted

技术标签:

【中文标题】Python:从父子值列表创建嵌套字典【英文标题】:Python: create a nested dictionary from a list of parent child values 【发布时间】:2015-07-27 00:55:07 【问题描述】:

这是输入:

list_child_parent= [
    #first value is child, second is parent
    (0, 1),
    (1, 3),
    (8, 7),
    (3, 6),
    (4, 3),
    (5, 3)
]

输出需要使用这些值创建一个嵌套字典树。树的深度永远不会超过 6 层。

例如:

output_dict = 
    6: 3: 1: 0: , 4: , 5: , 7: 8: 

我花了两天时间试图完成这个。我曾尝试编写函数来查找键在树中的位置,然后在其后添加新键,但我无法生成可以继续超过 3 个级别的代码。这令人费解,我觉得可能有一个标准库可以做到这一点。

我的经验水平很低。

【问题讨论】:

根据您的“示例输出”,3 是 8 的父级。但这不是您的输入所描述的。此外, 8 不应该是 7 的 child 吗?我很困惑。 key: value 对是否存在模式? 3 是 1、4 和 5 的父级。是的 8 是 7 的子级,我修复了这个问题。显然我还没有产生输出的代码,所以我手工编写了那个字典。 这对没有模式。您应该假设父子巢穴的列表可以按任何顺序排列。 你的树不应该是6: 3: 1: 0: , 4: , 5: , 7: 8: 吗?您显示 3 在元组中有子 1、5、4,但输出看起来像 1 有子 5、4、0。 【参考方案1】:

不漂亮,可能不是 Pythonic,但它应该能让你继续前进:

#!/usr/bin/env python3

def make_map(list_child_parent):
    has_parent = set()
    all_items = 
    for child, parent in list_child_parent:
        if parent not in all_items:
            all_items[parent] = 
        if child not in all_items:
            all_items[child] = 
        all_items[parent][child] = all_items[child]
        has_parent.add(child)

    result = 
    for key, value in all_items.items():
        if key not in has_parent:
            result[key] = value
    return result

if __name__ == '__main__':
    list_child_parent = [
        #first value is child, second is parent
        (0, 1),
        (1, 3),
        (8, 7),
        (3, 6),
        (4, 3),
        (5, 3)
    ]

    actual = make_map(list_child_parent)

    expected = 
        6: 
            3: 
                1: 
                    0: 
                ,
                4: ,
                5: 
            
        ,
        7: 
            8: 
        
    
    print('OK' if expected == actual else 'FAIL')

【讨论】:

这个解决方案效果很好。它将我的 45 行不起作用的代码浓缩成一个易于理解的简单解决方案。我以前从未见过 set() 以这种方式使用过,并且在阅读了 python 文档后你的用法并不明显。我应该注意,一旦构建了树,它就会保存在缓存中,因此性能不是问题。然而,有几千个父/子关系,并且随着新数据的添加,需要定期重建树。这可能会作为我正在构建的烧瓶网站的 cron 运行。 能否请您帮忙逆向,即从同一个嵌套字典中制作父子对? @user3156040 答案可能不适合评论。能否请您创建一个新问题,然后在此处发布链接?【参考方案2】:

此代码会将树从给定格式转换为树结构字典。这是很多绒毛,但它有助于跟踪正在发生的事情。性能方面还是不错的。

LIST_CHILD_PARENTS = [                                                     
#first value is child, second is parent                                    
(0, 1),                                                                    
(1, 3),                                                                    
(8, 7),                                                                    
(3, 6),                                                                    
(4, 3),                                                                    
(5, 3)                                                                     
]                                                                          


class Node(object):                                                        
    def __init__(self, value):                    
        self.value = value
        # List of references to Node()'s.                                                
        self.child = []              
        # Reference to parent Node()                                                                           
        self.parent = None                                               
    def set_parent(self, parent):                                          
        self.parent = parent                                               
    def set_child(self, child):                                            
        self.child.append(child)                                           


def get_a_root(items):                                                     
    """Find a root node from items.                                        

    Grab some node and follow the parent pointers to a root.               
    """                                                                    
    cur_key = list(items.keys())[0]                                              
    while items[cur_key].parent is not None:                               
        cur_key = items[cur_key].parent.value                              
    parent = items[cur_key]                                                
    return parent                                                          

def extract_tree(items, root):                                             
    """Remove the tree from root in items.                                 
    """                                                                    
    cur_key = root.value                                                   
    this_node = items[cur_key]                                             
    if len(this_node.child) == 0:                                          
        items.pop(cur_key)                                                 
        return                                                             
    else:                                                                  
        for child in this_node.child:                                      
            extract_tree(items, child)                                     
        items.pop(cur_key)                                                  

def insert_from_root(tree, root):                                          
    """Insert the dictionary items from a tree.                            
    """                                                                    
    current = root                                                         
    if len(current.child) == 0:                                            
        tree[current.value] =                                            
        return                                                             
    else:                                                                  
        table =                                                          
        for child in current.child:                                        
            insert_from_root(table, child)                                 
        tree[current.value] = table                                                                                                

def build_graphs():                                                        
    """Map all input graphs into Node(object)'s.           

    Return: A hash table by value: Node(value, child, parent)              
    """                                                                    
    items =                                                              
    for child, parent in LIST_CHILD_PARENTS:                               
        if not child in items:                                       
            c_n = Node(child)  
            items[child] = c_n                 
        else:                                                              
            c_n = items[child]                                             
        if not parent in items:                                      
            p_n = Node(parent) 
            items[parent] = p_n                    
        else:                                                              
            p_n = items[parent]                                            
        p_n.set_child(c_n)                                                 
        c_n.set_parent(p_n)                                                                                       
    return items                                                           

def run_dict_builder():                                                    
    """Map the graphs from input and map into a dict.                                  

    Sequence:                                                              
        1- Map all graphs from input trees: list(tuple)             
        2- For each root node:                                             
            2A - Get a root node.                                      
            2B - Extract tree under this root from graphs list.                  
            2C - Insert the tree from this root into dict.                      
        3- Return the Dictionary Tree structure.                                                     
    """                                                                    
    graphs = build_graphs()                                                

    h_table =                                                            
    while len(graphs) > 0:                                                 
        root = get_a_root(graphs)                                          
        extract_tree(graphs, root)                                
        insert_from_root(h_table, root)                          
    return h_table                                                         

print(run_dict_builder())

【讨论】:

Matt,感谢您提供了非常好的解决方案。这行得通,但我需要在 python 3 环境中使用它(应该指定 - 对不起!)。我将如何更改第 67 行的 items.has_key 以使其与 python 3 一起使用? AttributeError: 'dict' object has no attribute 'has_key' @DanSafee 您可以改用:if parent in items:if key in dict:

以上是关于Python:从父子值列表创建嵌套字典的主要内容,如果未能解决你的问题,请参考以下文章

如何创建具有一个索引键列和多个值列的字典

python 如何对嵌套字典里的数据进行添加和删除?

Python - 将字典列表附加到嵌套的默认字典时出现关键错误

使用Python从CSV文件创建嵌套字典

Robot Framework_004——字典的创建、合并和嵌套

dataframe中stu用法