【问题标题】:python dict key order based on values - recursive solution基于值的python dict键顺序 - 递归解决方案
【发布时间】:2019-02-25 05:30:47
【问题描述】:

(在 python 3.6 中) 如何输出字典键的列表,其中列表的顺序基于字典值依赖项?例如,如果我有一个软件程序字典,其中的值指示它所依赖的其他程序:

packages = { 'B7': ['R3'], 
             'R3': ['timestmp', 'Abbot', '9K'],
             'tempor': ['cavie', 'sandals', 'B7'],
             'Abbot': ['Duns'],
             'timestmp': [],
             'Duns': [] }

我会返回一个列表,其中包含根据安装所需的程序排序的每个项目。所以我会在“R3”之前安装“timestmp”。

>>> get_download_order(packages)
['timestmp', 'Duns', 'Abbot', '9K', 'R3', 'B7', 'cavie', 'sandals', 'tempor']

# The list doesn't have to result in this exact order 
# as long as the download order of packages will work. 

对于非递归解决方案,我正在考虑用孩子做一棵树,并确定父母,然后你可以遍历树。但显然,有一个递归的解决方案,我想不通。

【问题讨论】:

    标签: python sorting dictionary recursion dependencies


    【解决方案1】:

    您的问题被称为topological sort,来自维基百科:

    在计算机科学领域,拓扑排序或拓扑 有向图的排序是其顶点的线性排序,例如 对于从顶点 u 到顶点 v 的每条有向边 uv,u 来 顺序中的 v 之前。

    在您的特定情况下,图的顶点是包,边是依赖项。您可以使用Kahn's algorithm(无递归)解决问题,实现如下:

    def toposort(graph):
        # init the indegree for each noe
        nodes = graph.keys() | set([node for adjacents in graph.values() for node in adjacents])
        in_degree = {node: 0 for node in nodes}
    
        # compute the indegree
        for k, adjacents in graph.items():
            for node in adjacents:
                in_degree[node] += 1
    
        # init the heap with the nodes with indegree 0 and priority given by key
        heap = [node for node, degree in in_degree.items() if degree == 0]
    
        top_order = []
        while heap:  # heap is not empty
            node = heap.pop()  # get the element with highest priority and remove from heap
            top_order.append(node)  # add to topological order
            for adjacent in graph.get(node, []):  # iter over the neighbors of the node
                in_degree[adjacent] -= 1
                if in_degree[adjacent] == 0:  # if the node has in_degree 0 add to the heap with priority given by key
                    heap.append(adjacent)
    
        return top_order
    
    
    packages = {'B7': ['R3'],
                'R3': ['timestmp', 'Abbot', '9K'],
                'tempor': ['cavie', 'sandals', 'B7'],
                'Abbot': ['Duns'],
                'timestmp': [],
                'Duns': []}
    
    reverse = {}
    for key, nodes in packages.items():
        for node in nodes:
            reverse.setdefault(node, []).append(key)
    
    
    print(toposort(reverse))
    

    输出

    ['timestmp', '9K', 'sandals', 'Duns', 'Abbot', 'R3', 'B7', 'cavie', 'tempor']
    

    注意

    为了使提议的解决方案起作用,它需要反转图,这就是以下几行的作用:

    reverse = {}
    for key, nodes in packages.items():
        for node in nodes:
            reverse.setdefault(node, []).append(key)
    

    另请注意,顺序不是唯一的,例如在您的示例中,'timestmp' 和 'Duns' 都可能是第一个要安装的包,因为它们没有任何依赖项。

    进一步

    • Kanh 算法及其实现的讨论:topological sorting。
    • 递归解决方案可以使用(递归)深度优先搜索 (DFS) 来解决拓扑排序,您可以找到关于递归 DFS 的一个很好的讨论here。
    • 如需使用 DFS 解决拓扑排序,请参阅 this。

    【讨论】:

    • 如果没有依赖项,此解决方案将失败,您可以通过设置 packages = {"B7": [], "R3": []} 进行验证(它返回一个空列表)。
    【解决方案2】:

    改编自this answer:

    from typing import List, Dict, Set
    
    def topological_sort(graph: Dict[str, List[str]]) -> List[str]:
        result: List[str] = []
        seen: Set[str] = set()
    
        def recursive_helper(node: str) -> None:
            for neighbor in graph.get(node, []):
                if neighbor not in seen:
                    seen.add(neighbor)
                    recursive_helper(neighbor)
            if node not in result:
                result.append(node)
    
        for key in graph.keys():
            recursive_helper(key)
        return result
    
    
    packages = {'B7': ['R3'],
                'R3': ['timestmp', 'Abbot', '9K'],
                'tempor': ['cavie', 'sandals', 'B7'],
                'Abbot': ['Duns'],
                'timestmp': [],
                'Duns': []}
    
    print(topological_sort(packages))
    

    输出

    ['timestmp', 'Duns', 'Abbot', '9K', 'R3', 'B7', 'cavie', 'sandals', 'tempor']
    

    这也可以在没有依赖关系的情况下工作:

    packages = {"B7": [], "R3": []}
    print(topological_sort(packages))
    

    输出

    ['B7', 'R3]
    

    【讨论】:

      猜你喜欢
      • 2021-11-03
      • 1970-01-01
      • 2021-10-24
      • 2013-07-22
      • 2011-12-10
      • 2015-10-25
      • 1970-01-01
      • 1970-01-01
      • 2014-10-28
      相关资源
      最近更新 更多