Last active
October 9, 2021 02:01
-
-
Save mrecachinas/0704e8110983fff94ae9 to your computer and use it in GitHub Desktop.
First topological sort written in Apple's new language Swift.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// First Topological Sort in Apple's new language Swift | |
// Updated on 10/30/2016 to account for the newest version of Swift (3.0) | |
// Michael Recachinas | |
enum TopologicalSortError : Error { | |
case CycleError(String) | |
} | |
/// Simple helper method to check if a graph is empty | |
/// - parameters: | |
/// - dependency_list: a `Dictionary<String, [String]>` containing the graph structure | |
/// - returns: a `Bool` that determines whether or not the values in a dictionary are empty | |
func isEmpty(graph: Dictionary<String, [String]>) -> Bool { | |
for (_, value) in graph { | |
if value.count > 0 { | |
return false | |
} | |
} | |
return true | |
} | |
/// Performs the topological sort | |
/// - parameters: | |
/// - dependency_list | |
/// - returns: a sorted `[String]` containing a possible topologically sorted path | |
/// - throws: a `TopologicalSortError.CycleError` if the graph is not empty (meaning there exists a cycle) | |
func topo_sort(dependency_list: Dictionary<String, [String]>) throws -> [String] { | |
var sorted: [String] = [] | |
var next_depth: [String] = [] | |
var graph = dependency_list | |
for key in graph.keys { | |
if graph[key]! == [] { | |
next_depth.append(key) | |
} | |
} | |
for key in next_depth { | |
graph.removeValue(forKey: key) | |
} | |
while next_depth.count != 0 { | |
next_depth.sort(by: >) | |
let node = next_depth.removeLast() | |
sorted.append(node) | |
for key in graph.keys { | |
let arr = graph[key] | |
let dl = arr!.filter({ $0 == node}) | |
if dl.count > 0 { | |
graph[key] = graph[key]?.filter({$0 != node}) | |
if graph[key]?.count == 0 { | |
next_depth.append(key) | |
} | |
} | |
} | |
} | |
if !isEmpty(graph: graph) { | |
throw TopologicalSortError.CycleError("This graph contains a cycle.") | |
} | |
else { | |
return sorted | |
} | |
} | |
// Tests | |
let no_cycle: Dictionary<String, [String]> = [ | |
"Buy Swift Manual": [], | |
"Buy iPhone": [], | |
"Learn Swift": ["Read Swift Manual"], | |
"Read Swift Manual": ["Buy Swift Manual"], | |
"Write iPhone App": ["Learn Swift", "Buy iPhone"], | |
"Make $$$": ["Write iPhone App"] | |
] | |
//------Test 1: No Cycle------ | |
//Result: | |
//Buy Swift Manual | |
//Buy iPhone | |
//Read Swift Manual | |
//Learn Swift | |
//Write iPhone App | |
//Make $$$ | |
print("------Test 1: No Cycle------\nResult:") | |
do { | |
for task in try topo_sort(dependency_list: no_cycle) { | |
print(task) | |
} | |
} catch TopologicalSortError.CycleError(let message) { | |
print(message) | |
} | |
let cycle: Dictionary<String, [String]> = [ | |
"Buy Swift Manual": [], | |
"Buy iPhone": ["Make $$$"], | |
"Learn Swift": ["Read Swift Manual"], | |
"Read Swift Manual": ["Buy Swift Manual"], | |
"Write iPhone App": ["Learn Swift", "Buy iPhone"], | |
"Make $$$": ["Write iPhone App"], | |
] | |
//------Test 2: Cycle------ | |
//Result: | |
//cycle | |
print("------Test 2: Cycle------\nResult:") | |
do { | |
for task in try topo_sort(dependency_list: cycle) { | |
print(task) | |
} | |
} catch TopologicalSortError.CycleError(let message) { | |
print(message) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment