Your problem is known as topological sort, from the Wikipedia:
In the field of computer science, a topological sort or topological
ordering of a directed graph is a linear ordering of its vertices such
that for every directed edge uv from vertex u to vertex v, u comes
before v in the ordering.
In your particular case the vertex of the graph are the packages and the edges are the dependencies. You can solve the problem using Kahn's algorithm (no recursion), an implementation below:
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))
Output
['timestmp', '9K', 'sandals', 'Duns', 'Abbot', 'R3', 'B7', 'cavie', 'tempor']
Note
For the proposed solution to work it needs the reversed graph, that is what the following lines do:
reverse = {}
for key, nodes in packages.items():
for node in nodes:
reverse.setdefault(node, []).append(key)
Also note that the order is not unique, for instance in your example both 'timestmp'
and 'Duns'
could be the first package to install, given that they don't have any dependencies.
Further
- A discussion of Kanh's algorithm along with implementations: topological sorting.
- A recursive solution can be done using (a recursive) Depth-First Search (DFS) to solve the topological sort, you can find a good discussion of a recursive DFS here.
- For using DFS for solving Topological sorting see this.