python dict基于值的键顺序-递归解决方案

时间:2018-09-20 20:39:46

标签: python sorting dictionary recursion dependencies

(在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. 

对于非递归解决方案,我正在考虑与孩子一起做一棵树,并确定父树,然后可以遍历树。但是显然,有一个递归解决方案,我无法弄清楚。

2 个答案:

答案 0 :(得分:0)

您的问题在维基百科上被称为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

答案 1 :(得分:0)

改编自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]