(在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.
对于非递归解决方案,我正在考虑与孩子一起做一棵树,并确定父树,然后可以遍历树。但是显然,有一个递归解决方案,我无法弄清楚。
答案 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'
可能是第一个要安装的软件包,因为它们没有任何依赖性。
进一步
答案 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]