Topological sort/Extracted top item: Difference between revisions

 
(22 intermediate revisions by 10 users not shown)
Line 1:
{{draft task|Sorting Algorithms}}
{{Sorting Algorithm}}
[[Category:Sorting]]
 
Given a mapping between items, and items they depend on, a [[wp:Topological sorting|topological sort]] orders items so that no item precedes an item it depends upon.
 
Line 36 ⟶ 39:
<small>Note: this task differs from task [[Topological sort]] in that the order for compiling any file might not include all files; and that checks for dependency cycles are not mandated.</small>
<br><br>
;Related task:
; Cf.
* [[Topological sort]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F _topx(data, tops, &_sofar) -> [[String]]
‘Recursive topological extractor’
_sofar [+]= copy(tops)
V depends = Set[String]()
L(top) tops
I top C data
depends.update(data[top])
I !depends.empty
_topx(data, depends, &_sofar)
[[String]] ordered
V accum = Set[String]()
L(i) (_sofar.len-1 .. 0).step(-1)
ordered [+]= sorted(Array(_sofar[i] - accum))
accum.update(_sofar[i])
R ordered
 
F toplevels(&data)
Extract all top levels from dependency data
Top levels are never dependents
L(k, v) data
v.discard(k)
Set[String] dependents
L(k, v) data
dependents.update(v)
R Set(data.keys()) - dependents
 
F topx(&data, tops)
‘Extract the set of top-level(s) in topological order’
L(k, v) data
v.discard(k)
[Set[String]] _sofar
R _topx(data, tops, &_sofar)
 
F printorder(order)
‘Prettyprint topological ordering’
I !order.empty
print(‘First: ’order[0].map(s -> String(s)).join(‘, ’))
L(o) order[1..]
print(‘ Then: ’o.map(s -> String(s)).join(‘, ’))
 
V data = [
‘top1’ = Set([‘ip1’, ‘des1’, ‘ip2’]),
‘top2’ = Set([‘ip2’, ‘des1’, ‘ip3’]),
‘des1’ = Set([‘des1a’, ‘des1b’, ‘des1c’]),
‘des1a’ = Set([‘des1a1’, ‘des1a2’]),
‘des1c’ = Set([‘des1c1’, ‘extra1’]),
‘ip2’ = Set([‘ip2a’, ‘ip2b’, ‘ip2c’, ‘ipcommon’]),
‘ip1’ = Set([‘ip1a’, ‘ipcommon’, ‘extra1’])
]
 
V tops = toplevels(&data)
print(‘The top levels of the dependency graph are: ’Array(tops).join(‘ ’))
 
L(t) sorted(Array(tops))
print("\nThe compile order for top level: #. is...".format(t))
printorder(topx(&data, Set([t])))
I tops.len > 1
print("\nThe compile order for top levels: #. is...".format(sorted(Array(tops)).map(s -> String(s)).join(‘ and ’)))
printorder(topx(&data, tops))</syntaxhighlight>
 
{{out}}
<pre>
The top levels of the dependency graph are: top1 top2
 
The compile order for top level: top1 is...
First: des1a1, des1a2, des1c1, extra1
Then: des1a, des1b, des1c, ip1a, ip2a, ip2b, ip2c, ipcommon
Then: des1, ip1, ip2
Then: top1
 
The compile order for top level: top2 is...
First: des1a1, des1a2, des1c1, extra1
Then: des1a, des1b, des1c, ip2a, ip2b, ip2c, ipcommon
Then: des1, ip2, ip3
Then: top2
 
The compile order for top levels: top1 and top2 is...
First: des1a1, des1a2, des1c1, extra1
Then: des1a, des1b, des1c, ip1a, ip2a, ip2b, ip2c, ipcommon
Then: des1, ip1, ip2, ip3
Then: top1, top2
</pre>
 
=={{header|C}}==
Take code from [[Topological sort#c]] and add/change the following:
<langsyntaxhighlight lang="c">char input[] = "top1 des1 ip1 ip2\n"
"top2 des1 ip2 ip3\n"
"ip1 extra1 ip1a ipcommon\n"
Line 115 ⟶ 207:
 
return 0;
}</langsyntaxhighlight>output (the last item is just to show that it doesn't have to be top level)<syntaxhighlight lang="text">Compile order for: top1
level 1: extra1 ip1a ipcommon ip2a ip2b ip2c des1b des1a1 des1a2 des1c1
level 2: ip1 ip2 des1a des1c
Line 135 ⟶ 227:
Compile order for: ip1
level 1: extra1 ip1a ipcommon
level 2: ip1</langsyntaxhighlight>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 297 ⟶ 389:
}
return L[i:], nil
}</langsyntaxhighlight>
{{out}}
<pre>
Line 313 ⟶ 405:
Derived from the [[Topological sort#J|topological sort]] implementation:
 
<langsyntaxhighlight lang="j">compileOrder=: dyad define
targets=. ;: x
parsed=. <@;:;._2 y
Line 325 ⟶ 417:
 
topLevel=: [: ({.&> -. [:;}.&.>) <@;:;._2
</syntaxhighlight>
</lang>
 
The changes include:
Line 339 ⟶ 431:
Example:
 
<langsyntaxhighlight lang="j">dependencies=: noun define
top1 des1 ip1 ip2
top2 des1 ip2 ip3
Line 370 ⟶ 462:
des1
top1 top2
</syntaxhighlight>
</lang>
 
=={{header|Java}}==
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import java.util.*;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
Line 402 ⟶ 494:
class Graph {
List<String> vertices;
intboolean[][] adjacency;
int numVertices;
 
Line 408 ⟶ 500:
vertices = asList(s.split(","));
numVertices = vertices.size();
adjacency = new intboolean[numVertices][numVertices];
 
for (int[] edge : edges)
adjacency[edge[0]][edge[1]] = 1true;
}
 
List<String> toplevels() {
List<String> result = new ArrayList<>();
// look for empty columns
outer:
for (int c = 0; c < numVertices; c++) {
for (int r = 0; r < numVertices; r++) {
if (adjacency[r][c] > 0)
continue outer;
}
Line 434 ⟶ 527:
 
while (!queue.isEmpty()) {
Integerint r = queue.poll();
for (int c = 0; c < numVertices; c++) {
if (adjacency[r][c] > 0 && !queue.contains(c)) {
queue.add(c);
}
Line 444 ⟶ 537:
return result.stream().distinct().collect(toList());
}
}</langsyntaxhighlight>
<pre>Top levels: [top1, top2]
Compile order for top1 [extra1, des1c1, des1a2, des1a1, des1c, des1b, des1a, ip2c, ip2b, ip2a, ipcommon, ip1a, des1, ip2, ip1, top1]
Line 450 ⟶ 543:
Compile order for ip1 [extra1, ipcommon, ip1a, ip1]</pre>
 
=={{header|Perl 6jq}}==
'''Works with jq, the C implementation of jq'''
<lang perl6>sub top_topos ( %deps, *@top ) {
my %ba;
for %deps.kv -> $after, @befores {
for @befores -> $before {
%ba{$after}{$before} = 0 if $before ne $after;
%ba{$before} //= {};
}
}
 
The program can easily be modified to work with gojq,
if @top {
the Go implementation of jq, by changing `keys_unsorted` to `keys`.
my @want = @top;
 
my %care;
The program has largely been adapted from [[#Wren|Wren]] but here the
%care{@want} = 1 xx *;
dependencies are specified naturally in terms of the file names,
repeat while @want {
and care is taken to address the task requirements that
my @newwant;
self-dependence is ignored, and that the specified ordering of
for @want -> $before {
independents is respected. Additionally, cycles are ignored.
if %ba{$before} {
 
for %ba{$before}.keys -> $after {
These aspects can be seen by defining `deps` as:
if not %ba{$before}{$after} {
<pre>
%ba{$before}{$after}++;
{ "top1": ["top2", "x", "y", "z"], "top2": ["top1", "x", "y", "z"] }
push @newwant, $after;
</pre>
}
In this case, the result for `top1` would be:
}
<pre>
}
A compilation order for top1:
}
top2 x y z top1
@want = @newwant;
</pre>
%care{@want} = 1 xx *;
 
}
<syntaxhighlight lang="jq">
# Emit a stream of first occurrences of items in the stream
def firsts(stream):
foreach stream as $x (null;
($x|tostring) as $s
| if . == null or .[$s] == null then .[$s] = $x | .emit = $x
elif .[$s] then .emit = null
else .emit = null
end;
select(.emit).emit);
 
# {numVertices, vertices, adjacency }
for %ba.keys -> $before {
def Graph($edges):
%ba{$before}:delete unless %care{$before};
# Use `reverse` to ensure the ordering of independents is respected
}
([firsts($edges | keys_unsorted[], .[][])] | reverse) as $vertices
| ($vertices|length) as $nv
| reduce ($edges | keys_unsorted[]) as $k ({};
reduce ($edges[$k][]) as $v (.;
if $k == $v then . # ignore self-dependencies
else .[$k][$v] = true
end ) )
| {$vertices, numVertices: $nv, adjacency: .} ;
 
# Input: a Graph
def topLevels:
.result = []
# look for empty columns
| reduce .vertices[] as $c (.;
.outer = false
| .r = 0
| until(.outer or .r == .numVertices;
if .adjacency[.vertices[.r]][$c]
then .outer = true
end
| .r += 1 )
| if .outer == false then .result += [$c] end
)
| .result;
 
# Input: a Graph
def compileOrder($item):
. + {result: [], queue: [$item] }
| until (.queue | length == 0;
.queue[0] as $r
| .queue |= .[1:]
# Ignore cycles by subtracting .result:
| reduce (.vertices - .result)[] as $c (.;
if .adjacency[$r][$c] and (.queue|index($c) == null)
then .queue += [$c]
end )
| .result = [$r] + .result
)
| [firsts(.result[])];
 
### An example
 
def deps: {
"top1" : ["ip1", "des1", "ip2"],
"top2" : ["ip2", "des1", "ip3"],
"des1" : ["des1a", "des1b", "des1c"],
"des1a": ["des1a1", "des1a2"],
"des1c": ["des1c1", "extra1"],
"ip2" : ["ip2a", "ip2b", "ip2c", "ipcommon"],
"ip1" : ["ip1a", "ipcommon", "extra1"]
};
 
def files: ["top1", "top2", "ip1"];
 
Graph(deps)
| "Top levels: \(topLevels)",
(files[] as $f
| "\nA compilation order for \($f):",
(compileOrder($f)|join(" ")) )
 
</syntaxhighlight>
{{output}}
<pre>
Top levels: ["top2","top1"]
 
A compilation order for top1:
des1a1 des1a2 des1c1 des1a des1c des1b ip2a ip2b ip2c extra1 ipcommon ip1a des1 ip2 ip1 top1
 
A compilation order for top2:
des1a1 des1a2 des1c1 extra1 des1a des1c des1b ip2a ip2b ip2c ipcommon des1 ip2 ip3 top2
 
A compilation order for ip1:
extra1 ipcommon ip1a ip1
</pre>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">const topotext = """
top1 des1 ip1 ip2
top2 des1 ip2 ip3
ip1 extra1 ip1a ipcommon
ip2 ip2a ip2b ip2c ipcommon
des1 des1a des1b des1c
des1a des1a1 des1a2
des1c des1c1 extra1
"""
 
const topolines = map(x -> split(x, r"\s+", limit=2), split(strip(topotext), "\n"))
const topodict = Dict([p[1] => split(p[2], r"\s+") for p in topolines])
 
const dependents = collect(keys(topodict))
const dependencies = string.(unique(mapreduce(x -> topodict[x], vcat, dependents)))
const toplevel = string.(filter(x -> !(x in dependencies), dependents))
 
println("Top level files: ", toplevel)
println("Dependencies: $dependencies\n")
 
function compileorder(file, ddict)
tocompile = [file]
firstdependencies = get(ddict, file, [])
if !isempty(firstdependencies)
for f in firstdependencies
append!(tocompile, reverse(compileorder(f, ddict)))
end
end
return unique(reverse(tocompile))
end
 
for f in toplevel
println("Compile order for $f: ", compileorder("top1", topodict))
end
</syntaxhighlight>{{out}}
<pre>
Top level files: ["top2", "top1"]
Dependencies: ["des1a", "des1b", "des1c", "ip2a", "ip2b", "ip2c", "ipcommon", "des1c1", "extra1", "des1a1", "des1a2", "des1", "ip2", "ip3", "ip1", "ip1a"]
 
Compile order for top2: ["ipcommon", "ip2c", "ip2b", "ip2a", "ip2", "ip1a", "extra1", "ip1", "des1c1", "des1c", "des1b", "des1a2", "des1a1", "des1a", "des1", "top1"]
Compile order for top1: ["ipcommon", "ip2c", "ip2b", "ip2a", "ip2", "ip1a", "extra1", "ip1", "des1c1", "des1c", "des1b", "des1a2", "des1a1", "des1a", "des1", "top1"]
</pre>
 
=={{header|Kotlin}}==
{{trans|Java}}
<syntaxhighlight lang="scala">// version 1.1.51
 
import java.util.LinkedList
 
val s = "top1, top2, ip1, ip2, ip3, ip1a, ip2a, ip2b, ip2c, ipcommon, des1, " +
"des1a, des1b, des1c, des1a1, des1a2, des1c1, extra1"
 
val deps = mutableListOf(
0 to 10, 0 to 2, 0 to 3,
1 to 10, 1 to 3, 1 to 4,
2 to 17, 2 to 5, 2 to 9,
3 to 6, 3 to 7, 3 to 8, 3 to 9,
10 to 11, 10 to 12, 10 to 13,
11 to 14, 11 to 15,
13 to 16, 13 to 17
)
 
val files = listOf("top1", "top2", "ip1")
 
class Graph(s: String, edges: List<Pair<Int, Int>>) {
 
val vertices = s.split(", ")
val numVertices = vertices.size
val adjacency = List(numVertices) { BooleanArray(numVertices) }
 
init {
for (edge in edges) adjacency[edge.first][edge.second] = true
}
 
fun topLevels(): List<String> {
my @levels;
val result = mutableListOf<String>()
while %ba.grep( not *.value )».key -> @befores {
// look for empty columns
push @levels, ~@befores.sort;
outer@ for (c in 0 until numVertices) {
%ba{@befores}:delete;
for %ba.values(r {in .{@befores}:delete0 }until numVertices) {
if (adjacency[r][c]) continue@outer
}
result.add(vertices[c])
}
return result
}
 
if @top {
fun compileOrder(item: String): List<String> {
say "For top-level-modules: ", @top;
val result = LinkedList<String>()
say " $_" for @levels;
val queue = LinkedList<Int>()
queue.add(vertices.indexOf(item))
while (!queue.isEmpty()) {
val r = queue.poll()
for (c in 0 until numVertices) {
if (adjacency[r][c] && !queue.contains(c)) queue.add(c)
}
result.addFirst(vertices[r])
}
return result.distinct().toList()
}
else {
say "Top levels are: @levels[*-1]";
}
say "Cycle found! {%ba.keys.sort}" if %ba;
say '';
}
 
fun main(args: Array<String>) {
my %deps =
top1val g => Graph(s, <des1 ip1 ip2>,deps)
println("Top levels: ${g.topLevels()}")
top2 => <des1 ip2 ip3>,
for (f in files) println("\nCompile order for $f: ${g.compileOrder(f)}")
ip1 => <extra1 ip1a ipcommon>,
}</syntaxhighlight>
ip2 => <ip2a ip2b ip2c ipcommon>,
 
des1 => <des1a des1b des1c>,
des1a => <des1a1 des1a2>,
des1c => <des1c1 extra1>;
top_topos(%deps);
top_topos(%deps, 'top1');
top_topos(%deps, 'top2');
top_topos(%deps, 'ip1');
top_topos(%deps, 'top1', 'top2');</lang>
{{out}}
<pre>
<pre>Top levels are: top1 top2
Top levels: [top1, top2]
 
Compile order for top1: [extra1, des1c1, des1a2, des1a1, des1c, des1b, des1a, ip2c, ip2b, ip2a, ipcommon, ip1a, des1, ip2, ip1, top1]
For top-level-modules: top1
des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ipcommon
des1a des1c ip1 ip2
des1
top1
 
Compile order for top2: [extra1, des1c1, des1a2, des1a1, des1c, des1b, des1a, ipcommon, ip2c, ip2b, ip2a, des1, ip3, ip2, top2]
For top-level-modules: top2
des1a1 des1a2 des1b des1c1 extra1 ip2a ip2b ip2c ip3 ipcommon
des1a des1c ip2
des1
top2
 
Compile order for ip1: [extra1, ipcommon, ip1a, ip1]
For top-level-modules: ip1
</pre>
extra1 ip1a ipcommon
ip1
 
=={{header|Nim}}==
For top-level-modules: top1 top2
{{trans|Python}}
des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ip3 ipcommon
<syntaxhighlight lang="nim">import algorithm, sequtils, strutils, sets, tables
des1a des1c ip1 ip2
 
des1
type
top1 top2
StringSet = HashSet[string]
StringSeq = seq[string]
 
const Empty: StringSet = initHashSet[string]()
 
 
func topLevels(data: Table[string, StringSet]): StringSet =
## Extract all top levels from dependency data.
 
# Remove self dependencies.
var data = data
for key, values in data.mpairs:
values.excl key
 
let deps = toSeq(data.values).foldl(a + b)
result = toSeq(data.keys).toHashSet - deps
 
 
func topx(data: Table[string, StringSet]; tops: StringSet;
sofar: var seq[StringSet]): seq[StringSeq] =
## Recursive topological extractor.
sofar = sofar & tops
var depends: StringSet
for top in tops:
depends = depends + data.getOrDefault(top, Empty)
if depends.card != 0: discard data.topx(depends, sofar)
var accum = Empty
for i in countdown(sofar.high, 0):
result.add sorted(toSeq(sofar[i] - accum))
accum = accum + sofar[i]
 
 
func topx(data: Table[string, StringSet]; tops = initHashSet[string]()): seq[StringSeq] =
## Extract the set of top-level(s) in topological order.
 
# Remove self dependencies.
var data = data
for key, values in data.mpairs:
values.excl key
 
var tops = tops
if tops.card == 0: tops = data.topLevels
 
var sofar: seq[StringSet]
result = data.topx(tops, sofar)
 
 
proc printOrder(order: seq[StringSeq]) =
## Prettyprint topological ordering.
if order.len != 0:
echo "First: ", order[0].join(", ")
for i in 1..order.high:
echo " Then: ", order[i].join(", ")
 
 
when isMainModule:
 
const Data = {"top1": ["ip1", "des1", "ip2"].toHashSet,
"top2": ["ip2", "des1", "ip3"].toHashSet,
"des1": ["des1a", "des1b", "des1c"].toHashSet,
"des1a": ["des1a1", "des1a2"].toHashSet,
"des1c": ["des1c1", "extra1"].toHashSet,
"ip2": ["ip2a", "ip2b", "ip2c", "ipcommon"].toHashSet,
"ip1": ["ip1a", "ipcommon", "extra1"].toHashSet}.toTable
 
let tops = Data.topLevels()
let topList = sorted(tops.toSeq)
echo "The top levels of the dependency graph are: ", topList.join(", ")
for t in topList:
echo "\nThe compile order for top level “$#” is..." % t
printOrder Data.topx([t].toHashSet)
 
if tops.len > 1:
echo "\nThe compile order for top levels $# is..." % topList.mapIt("“" & it & "”").join(" and ")
printOrder Data.topx(tops)</syntaxhighlight>
 
{{out}}
<pre>The top levels of the dependency graph are: top1, top2
 
The compile order for top level “top1” is...
First: des1a1, des1a2, des1c1, extra1
Then: des1a, des1b, des1c, ip1a, ip2a, ip2b, ip2c, ipcommon
Then: des1, ip1, ip2
Then: top1
 
The compile order for top level “top2” is...
First: des1a1, des1a2, des1c1, extra1
Then: des1a, des1b, des1c, ip2a, ip2b, ip2c, ipcommon
Then: des1, ip2, ip3
Then: top2
 
The compile order for top levels “top1” and “top2” is...
First: des1a1, des1a2, des1c1, extra1
Then: des1a, des1b, des1c, ip1a, ip2a, ip2b, ip2c, ipcommon
Then: des1, ip1, ip2, ip3
Then: top1, top2</pre>
 
=={{header|Pascal}}==
Works with FPC (tested with version 3.2.2).
<syntaxhighlight lang="pascal">
program TopLevel;
{$mode delphi}
uses
SysUtils, Generics.Collections;
 
type
TAdjList = class
InList, // incoming arcs
OutList: THashSet<string>; // outcoming arcs
constructor Create;
destructor Destroy; override;
end;
 
TDigraph = class(TObjectDictionary<string, TAdjList>)
procedure AddNode(const s: string);
procedure AddArc(const s, t: string);
function AdjList(const s: string): TAdjList;
end;
 
constructor TAdjList.Create;
begin
InList := THashSet<string>.Create;
OutList := THashSet<string>.Create;
end;
 
destructor TAdjList.Destroy;
begin
InList.Free;
OutList.Free;
inherited;
end;
 
procedure TDigraph.AddNode(const s: string);
begin
if not ContainsKey(s) then
Add(s, TAdjList.Create);
end;
 
procedure TDigraph.AddArc(const s, t: string);
begin
AddNode(s);
AddNode(t);
if s <> t then begin
Items[s].OutList.Add(t);
Items[t].InList.Add(s);
end;
end;
 
function TDigraph.AdjList(const s: string): TAdjList;
begin
if not TryGetValue(s, Result) then
Result := nil;
end;
 
function GetCompOrder(g: TDigraph; const aTarget: string): TStringArray;
var
Stack: TList<string>;
Visited: THashSet<string>;
procedure Dfs(const aNode: string);
var
Next: string;
begin
Visited.Add(aNode);
for Next in g.AdjList(aNode).OutList do
if not Visited.Contains(Next) then
Dfs(Next);
Stack.Add(aNode);
end;
begin
if not g.ContainsKey(aTarget) then exit([aTarget]);
Stack := TList<string>.Create;
Visited := THashSet<string>.Create;
Dfs(aTarget);
Visited.Free;
Result := Stack.ToArray;
Stack.Free;
end;
 
function GetTopLevels(g: TDigraph): TStringArray;
var
List: TList<string>;
p: TPair<string, TAdjList>;
begin
List := TList<string>.Create;
for p in g do
with p.Value do
if (InList.Count = 0) and (OutList.Count <> 0) then
List.Add(p.Key);
Result := List.ToArray;
List.Free;
end;
 
function ParseRawData(const aData: string): TDigraph;
var
Line, Curr, Node: string;
FirstTerm: Boolean;
begin
Result := TDigraph.Create([doOwnsValues]);
for Line in aData.Split([LineEnding], TStringSplitOptions.ExcludeEmpty) do begin
FirstTerm := True;
for Curr in Line.Split([' '], TStringSplitOptions.ExcludeEmpty) do
if FirstTerm then begin
Node := Curr;
Result.AddNode(Curr);
FirstTerm := False;
end else
Result.AddArc(Node, Curr);
end;
end;
 
const
Data =
'top1 des1 ip1 ip2' + LineEnding +
'top2 des1 ip2 ip3' + LineEnding +
'ip1 extra1 ip1a ipcommon' + LineEnding +
'ip2 ip2a ip2b ip2c ipcommon' + LineEnding +
'des1 des1a des1b des1c' + LineEnding +
'des1a des1a1 des1a2' + LineEnding +
'des1c des1c1 extra1';
var
g: TDigraph;
begin
g := ParseRawData(Data);
WriteLn('Top levels: ', string.Join(', ', GetTopLevels(g)));
WriteLn;
WriteLn('Compile order for top1:', LineEnding, string.Join(', ', GetCompOrder(g, 'top1')));
WriteLn;
WriteLn('Compile order for top2:', LineEnding, string.Join(', ', GetCompOrder(g, 'top2')));
g.Free;
end.
</syntaxhighlight>
{{out}}
<pre>
Top levels: top2, top1
 
Compile order for top1:
extra1, ipcommon, ip1a, ip1, des1a2, des1a1, des1a, des1c1, des1c, des1b, des1, ip2c, ip2b, ip2a, ip2, top1
 
Compile order for top2:
des1a2, des1a1, des1a, extra1, des1c1, des1c, des1b, des1, ip2c, ip2b, ip2a, ipcommon, ip2, ip3, top2
</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict;
use warnings;
use List::Util qw( uniq );
 
my $deps = <<END;
top1 des1 ip1 ip2
top2 des1 ip2 ip3
ip1 extra1 ip1a ipcommon
ip2 ip2a ip2b ip2c ipcommon
des1 des1a des1b des1c
des1a des1a1 des1a2
des1c des1c1 extra1
END
 
sub before
{
map { $deps =~ /^$_\b(.+)/m ? before( split ' ', $1 ) : (), $_ } @_
}
 
1 while $deps =~ s/^(\w+)\b.*?\K\h+\1\b//gm; # remove self dependencies
print "TOP LEVELS: @{[grep $deps !~ /\h$_\b/, $deps =~ /^\w+/gm]}\n";
print "\nTARGET $_ ORDER: @{[ uniq before split ]}\n"
for $deps =~ /^\w+/gm, 'top1 top2';</syntaxhighlight>
{{out}}
<pre>
TOP LEVELS: top1 top2
 
TARGET top1 ORDER: des1a1 des1a2 des1a des1b des1c1 extra1 des1c des1 ip1a ipcommon ip1 ip2a ip2b ip2c ip2 top1
 
TARGET top2 ORDER: des1a1 des1a2 des1a des1b des1c1 extra1 des1c des1 ip2a ip2b ip2c ipcommon ip2 ip3 top2
 
TARGET ip1 ORDER: extra1 ip1a ipcommon ip1
 
TARGET ip2 ORDER: ip2a ip2b ip2c ipcommon ip2
 
TARGET des1 ORDER: des1a1 des1a2 des1a des1b des1c1 extra1 des1c des1
 
TARGET des1a ORDER: des1a1 des1a2 des1a
 
TARGET des1c ORDER: des1c1 extra1 des1c
 
TARGET top1 top2 ORDER: des1a1 des1a2 des1a des1b des1c1 extra1 des1c des1 ip1a ipcommon ip1 ip2a ip2b ip2c ip2 top1 ip3 top2
</pre>
 
=={{header|Phix}}==
Minor tweaks to the Topological_sort code: top_levels, propagate() and -1 now means "not required".
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #004080;">sequence</span> <span style="color: #000000;">names</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">RANK</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">NAME</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">DEP</span> <span style="color: #000080;font-style:italic;">-- content of names
-- rank is 1 for items to compile first, then 2, etc,
-- or 0 if cyclic dependencies prevent compilation.
-- - and -1 now means "not required".
-- name is handy, and makes the result order alphabetic!
-- dep is a list of dependencies (indexes to other names)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">add_dependency</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">,</span><span style="color: #000000;">NAME</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">names</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">,{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,{}})</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">k</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">propagate</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">propagate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">topsort</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">input</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">tops</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">names</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]),</span>
<span style="color: #000000;">dependencies</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add_dependency</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add_dependency</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">k</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- ignore self-references</span>
<span style="color: #000000;">dependencies</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">l</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dependencies</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">tops</span><span style="color: #0000FF;">={}</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- show top levels</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ji</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ji</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">top_levels</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">top_levels</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">top_levels</span><span style="color: #0000FF;">,</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">NAME</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"top levels: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">top_levels</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- Propagate required by setting RANK to 0:</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tops</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add_dependency</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tops</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">propagate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000080;font-style:italic;">-- Now populate names[RANK] iteratively:</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">more</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">rank</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">more</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">more</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #000000;">rank</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">ok</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ji</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">DEP</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">nr</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ji</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">nr</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">nr</span><span style="color: #0000FF;">=</span><span style="color: #000000;">rank</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- not yet compiled, or same pass</span>
<span style="color: #000000;">ok</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ok</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rank</span>
<span style="color: #000000;">more</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">names</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (ie by [RANK=1] then [NAME=2])</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">prank</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">rank</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">RANK</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rank</span><span style="color: #0000FF;">>-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rank</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prank</span><span style="color: #0000FF;">?</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"\nlevel %d:"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rank</span><span style="color: #0000FF;">)))</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">NAME</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">prank</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rank</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">input</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
top1 des1 ip1 ip2
top2 des1 ip2 ip3
ip1 extra1 ip1a ipcommon
ip2 ip2a ip2b ip2c ipcommon
des1 des1a des1b des1c
des1a des1a1 des1a2
des1c des1c1 extra1"""</span>
<span style="color: #000000;">topsort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,{})</span>
<span style="color: #000000;">topsort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"top1"</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">topsort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"top2"</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">topsort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"top1"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"top2"</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">topsort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"ip1"</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
Items on the same line can be compiled at the same time, and each line is alphabetic.
<pre>
top levels: top1 top2
 
level 1:des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ipcommon
level 2:des1a des1c ip1 ip2
level 3:des1
level 4:top1
 
level 1:des1a1 des1a2 des1b des1c1 extra1 ip2a ip2b ip2c ip3 ipcommon
level 2:des1a des1c ip2
level 3:des1
level 4:top2
 
level 1:des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ip3 ipcommon
level 2:des1a des1c ip1 ip2
level 3:des1
level 4:top1 top2
 
level 1:extra1 ip1a ipcommon
level 2:ip1
</pre>
 
=={{header|Python}}==
Where the compile order between a subset of files is arbitrary, they are shown on the same line.
<langsyntaxhighlight lang="python">try:
from functools import reduce
except: pass
Line 607 ⟶ 1,278:
print("\nThe compile order for top levels: %s is..."
% ' and '.join(str(s) for s in sorted(tops)) )
printorder(topx(data, tops))</langsyntaxhighlight>
 
'''Sample Output'''
Line 632 ⟶ 1,303:
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">#lang racket
(define dep-tree ; go straight for the hash, without parsing strings etc.
#hash((top1 . (des1 ip1 ip2))
Line 681 ⟶ 1,352:
(print-build-order dep-tree 'top2)
(with-handlers [(exn? (λ (x) (displayln (exn-message x) (current-error-port))))]
(build-tree #hash((top . (des1 ip1)) (ip1 . (net netip)) (netip . (mac ip1))) 'top))</langsyntaxhighlight>
 
{{out}}
Line 697 ⟶ 1,368:
 
build-tree: circular dependency tree at node: ip1</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub top_topos ( %deps, *@top ) {
my %ba;
for %deps.kv -> $after, @befores {
for @befores -> $before {
%ba{$after}{$before} = 0 if $before ne $after;
%ba{$before} //= {};
}
}
 
if @top {
my @want = @top;
my %care;
%care{@want} = 1 xx *;
repeat while @want {
my @newwant;
for @want -> $before {
if %ba{$before} {
for %ba{$before}.keys -> $after {
if not %ba{$before}{$after} {
%ba{$before}{$after}++;
push @newwant, $after;
}
}
}
}
@want = @newwant;
%care{@want} = 1 xx *;
}
 
for %ba.keys -> $before {
%ba{$before}:delete unless %care{$before};
}
}
my @levels;
while %ba.grep( not *.value )».key -> @befores {
push @levels, ~@befores.sort;
%ba{@befores}:delete;
for %ba.values { .{@befores}:delete }
}
if @top {
say "For top-level-modules: ", @top;
say " $_" for @levels;
}
else {
say "Top levels are: @levels[*-1]";
}
say "Cycle found! {%ba.keys.sort}" if %ba;
say '';
}
 
my %deps =
top1 => <des1 ip1 ip2>,
top2 => <des1 ip2 ip3>,
ip1 => <extra1 ip1a ipcommon>,
ip2 => <ip2a ip2b ip2c ipcommon>,
des1 => <des1a des1b des1c>,
des1a => <des1a1 des1a2>,
des1c => <des1c1 extra1>;
top_topos(%deps);
top_topos(%deps, 'top1');
top_topos(%deps, 'top2');
top_topos(%deps, 'ip1');
top_topos(%deps, 'top1', 'top2');</syntaxhighlight>
{{out}}
<pre>Top levels are: top1 top2
 
For top-level-modules: top1
des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ipcommon
des1a des1c ip1 ip2
des1
top1
 
For top-level-modules: top2
des1a1 des1a2 des1b des1c1 extra1 ip2a ip2b ip2c ip3 ipcommon
des1a des1c ip2
des1
top2
 
For top-level-modules: ip1
extra1 ip1a ipcommon
ip1
 
For top-level-modules: top1 top2
des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ip3 ipcommon
des1a des1c ip1 ip2
des1
top1 top2
</pre>
 
=={{header|REXX}}==
Where the compile order between a subset of files is arbitrary, they are shown on the same line.
<br>This REXX version can handle multiple top levels.
<syntaxhighlight lang REXX="rexx">/*REXX program display sdisplays the compile order of jobs (indicating the dependencies). */
parse arg job /*obtain optional argument from the CL.*/
jobL. =; stage.=; #.=0; @.=; JL= /*define some handy-dandyhandy─dandy variables. */
tree.=; tree.1= ' top1 des1 ip1 ip2 '
tree. =
tree.12= ' top1top2 des1 ip1ip2 ip2ip3 '
tree.2= ' top2 des1 ip2 ip3 tree.3= ' ip1 extra1 ip1a ipcommon '
tree.34= ' ip1ip2 extra1ip2a ip1a ip2b ipcommon ip2c ipcommon '
tree.45= ' ip2des1 des1a ip2ades1b des1c ip2b ip2c ipcommon '
tree.56= ' des1des1a des1a1 des1a des1a2 des1b des1c '
tree.67= ' des1ades1c des1a1des1c1 des1a2extra1 '
tree.7= ' des1c des1c1 extra1 '
$=
do j=1 while tree.j\=='' /*build job tree.*/
parse var tree.j x deps; @.x=space(deps) @.x= space(deps) /*extract jobs. */
if wordpos(x, $)==0 then $= $ x /*Unique? Add it.*/
do k=1 for words(@.x); _= word(@.x, k)
if wordpos(_, $)==0 then $= space($ _)
end /*k*/
end /*j*/
!.=; !!.= !. /*init. 2 arrays.*/
!.=; !!.=
do j=1 for words($); x= word($, j); !.x.0= words(@.x)
do k=1 for !.x.0; !.x.k= word(@.x, k); !!.x.k= !.x.k
end /*k*/ /* [↑] build arrays of job departments*/
end /*j*/
 
do words($) /*process all the jobs specified. */
do j=1 for words($); x= word($, j); z= words(@.x); allN= 1; m= 0
if z==0 then do; #.x=1; iterate; end /*if no dependents, then skip this one.*/
do k=1 for z; y=!.x.k y= !.x.k /*examine all the stage numbers. */
if datatype(y, 'W') then m= max(m, y) /*find the highest stage number. */
else do; allN=0 0 /*at least one entry isn't numeric. */
if #.y\==0 then !.x.k= #.y
end end /* [↑] replace with a number. */
end /*k*/
if allN & m\==0 then #.x= max(#.x, m + 1) /*replace with the stage number max. */
end /*j*/ /* [↑] maybe set the stage number. */
end /*words($)*/
 
jobL.1if job=job '' then job= word(tree.1, 1) /*defineNot thespecified? bottom level jobList. Use 1st job in tree.*/
s=jobL.1= job /*define the stagebottom level for jobList. */
s= 1 /*define the stage level for jobList. */
do j=1; yyy=jobL.j
do j=1; yyy= jobL.j
do r=1 for words(yyy) /*verify that there are no duplicates. */
do c=1 while c<words(yyy); z= word(yyy,c)
p= wordpos(z, yyy, c + 1); if p\==0 then yyy= delword(yyy, p, 1)
end /*c*/ /* [↑] DupDuplicate? Then delete it. */
end /*r*/
jobL.j= yyy
if yyy='' then leave /*if null, then we're done with jobList*/
z= words(yyy) /*number of jobs in the jobList. */
s= s+1 /*bump the stage number. */
do k=1 for z; _= word(yyy, k) /*obtain a stage number for the job. */
jobL.s= jobL.s @._ /*add a job to a stage. */
end /*k*/
end /*j*/
 
do k=1 for s; JL= JL jobL.k; end /*build a complete jobList (JL). */
end /*k*/
 
do s=1 for words(JL); _= word(JL, s) /*process each job in the jobList. */
_level=word(JL,s); #._ level=#._ /*get the proper level for the job. */
stage.level= stage.level _ /*assign a level to job stage number. */
end /*s*/ /* [↑] construct various job stages. */
 
say '─────── The compile order for job: ' job " ────────"; say
/* [↓] display the stages for the job.*/
do show=1 for s; if stage.show\=='' then say show stage.show; end
end /*show*/ /*stick a fork in it, we're all done. */</langsyntaxhighlight>
'''{{out|output''' |text=&nbsp; when using the default input of: &nbsp; <tt> top1 </tt>}}
<pre>
─────── The compile order for job: top1 ───────
 
1 des1b extra1 ip1a ipcommon ip2a ip2b ip2c des1a1 des1a2 des1c1 extra1
Line 776 ⟶ 1,542:
4 top1
</pre>
'''{{out|output''' |text=&nbsp; when using the input of: &nbsp; <tt> top2 </tt>}}
<pre>
─────── The compile order for job: top2 ───────
 
1 ip3 des1b ip2a ip2b ip2c ipcommon des1a1 des1a2 des1c1 extra1
Line 785 ⟶ 1,551:
4 top2
</pre>
'''{{out|output''' |text=&nbsp; when using the input of: &nbsp; <tt> top1 top2 </tt>}}
<pre>
─────── The compile order for job: top1 top2 ───────
 
1 ip3 des1b extra1 ip1a ipcommon ip2a ip2b ip2c des1a1 des1a2 des1c1 extra1
Line 799 ⟶ 1,565:
The <tt>topsort</tt> proc is taken from [[Topological sort#Tcl]] with <tt>{*}</tt> removed from the line commented so that results are returned by level:
 
<langsyntaxhighlight Tcllang="tcl">package require Tcl 8.5
proc topsort {data} {
# Clean the data
Line 891 ⟶ 1,657:
puts "\tround [incr i]:\t$deps"
}
}</langsyntaxhighlight>
 
{{out}}
Line 911 ⟶ 1,677:
round 3: des1
round 4: top2
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-llist}}
{{libheader|Wren-seq}}
<syntaxhighlight lang="wren">import "./llist" for DLinkedList
import "./seq" for Lst
 
var s = "top1, top2, ip1, ip2, ip3, ip1a, ip2a, ip2b, ip2c, ipcommon, des1, " +
"des1a, des1b, des1c, des1a1, des1a2, des1c1, extra1"
 
var deps = [
[ 0, 10], [ 0, 2], [ 0, 3],
[ 1, 10], [ 1, 3], [ 1, 4],
[ 2, 17], [ 2, 5], [ 2, 9],
[ 3, 6], [ 3, 7], [ 3, 8], [ 3, 9],
[10, 11], [10, 12], [10, 13],
[11, 14], [11, 15],
[13, 16], [13, 17],
]
 
var files = ["top1", "top2", "ip1"]
 
class Graph {
construct new(s, edges) {
_vertices = s.split(", ")
var nv = _vertices.count
_adjacency = List.filled(nv, null)
for (i in 0...nv) _adjacency[i] = List.filled(nv, false)
for (edge in edges) _adjacency[edge[0]][edge[1]] = true
_numVertices = nv
}
 
topLevels {
var result = []
// look for empty columns
for (c in 0..._numVertices) {
var outer = false
for (r in 0..._numVertices) {
if (_adjacency[r][c]) {
outer = true
break
}
}
if (!outer) result.add(_vertices[c])
}
return result
}
 
compileOrder(item) {
var result = DLinkedList.new()
var queue = DLinkedList.new()
queue.add(Lst.indexOf(_vertices, item))
while (!queue.isEmpty) {
var r = queue.removeAt(0)
for (c in 0..._numVertices) {
if (_adjacency[r][c] && !queue.contains(c)) queue.add(c)
}
result.prepend(_vertices[r])
}
return Lst.distinct(result.toList)
}
}
 
var g = Graph.new(s, deps)
System.print("Top levels: %(g.topLevels)")
for (f in files) System.print("\nCompile order for %(f): %(g.compileOrder(f))")</syntaxhighlight>
 
{{out}}
<pre>
Top levels: [top1, top2]
 
Compile order for top1: [extra1, des1c1, des1a2, des1a1, des1c, des1b, des1a, ip2c, ip2b, ip2a, ipcommon, ip1a, des1, ip2, ip1, top1]
 
Compile order for top2: [extra1, des1c1, des1a2, des1a1, des1c, des1b, des1a, ipcommon, ip2c, ip2b, ip2a, des1, ip3, ip2, top2]
 
Compile order for ip1: [extra1, ipcommon, ip1a, ip1]
</pre>
2,442

edits