Skip to content

Instantly share code, notes, and snippets.

@mrecachinas
Last active October 9, 2021 02:01
Show Gist options
  • Save mrecachinas/0704e8110983fff94ae9 to your computer and use it in GitHub Desktop.
Save mrecachinas/0704e8110983fff94ae9 to your computer and use it in GitHub Desktop.
First topological sort written in Apple's new language Swift.
// 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