From ac14a3199e37fc61b25df5d2e7e5a44eceb1fc28 Mon Sep 17 00:00:00 2001 From: Stuart Turner Date: Thu, 12 Oct 2023 16:20:07 -0500 Subject: [PATCH] Update documentation with `GetShortestPaths` --- ...erLinq.SuperEnumerable.GetShortestPaths.md | 13 ++ .../GetShortestPaths/GetShortestPaths1.linq | 52 ++++++ .../GetShortestPaths/GetShortestPaths2.linq | 49 ++++++ Source/SuperLinq/GetShortestPaths.cs | 155 +++++++++--------- 4 files changed, 190 insertions(+), 79 deletions(-) create mode 100644 Docs/SuperLinq.Docs/apidoc/SuperLinq.SuperEnumerable.GetShortestPaths.md create mode 100644 Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths1.linq create mode 100644 Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths2.linq diff --git a/Docs/SuperLinq.Docs/apidoc/SuperLinq.SuperEnumerable.GetShortestPaths.md b/Docs/SuperLinq.Docs/apidoc/SuperLinq.SuperEnumerable.GetShortestPaths.md new file mode 100644 index 00000000..1d2fd367 --- /dev/null +++ b/Docs/SuperLinq.Docs/apidoc/SuperLinq.SuperEnumerable.GetShortestPaths.md @@ -0,0 +1,13 @@ +--- +uid: SuperLinq.SuperEnumerable.GetShortestPaths``2(``0,System.Func{``0,``1,System.Collections.Generic.IEnumerable{System.ValueTuple{``0,``1}}}) +example: [*content] +--- +The following code example demonstrates how to use Dijkstra's algorithm to build a distance map using `GetShortestPaths`. +[!code-csharp[](SuperLinq/GetShortestPaths/GetShortestPaths1.linq#L6-)] + +--- +uid: SuperLinq.SuperEnumerable.GetShortestPaths``2(``0,System.Func{``0,``1,System.Collections.Generic.IEnumerable{System.ValueTuple{``0,``1}}},System.Collections.Generic.IEqualityComparer{``0},System.Collections.Generic.IComparer{``1}) +example: [*content] +--- +The following code example demonstrates how to use Dijkstra's algorithm to build a distance map using `GetShortestPaths`. +[!code-csharp[](SuperLinq/GetShortestPaths/GetShortestPaths2.linq#L6-)] diff --git a/Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths1.linq b/Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths1.linq new file mode 100644 index 00000000..173effa1 --- /dev/null +++ b/Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths1.linq @@ -0,0 +1,52 @@ + + SuperLinq + SuperLinq + + +var costs = + new[] + { + (from: "start", to: "a", cost: 1), + (from: "a", to: "b", cost: 2), + (from: "b", to: "c", cost: 3), + (from: "c", to: "d", cost: 4), + (from: "d", to: "end", cost: 5), + (from: "start", to: "A", cost: 10), + (from: "A", to: "B", cost: 20), + (from: "B", to: "C", cost: 30), + (from: "C", to: "D", cost: 40), + (from: "D", to: "end", cost: 50), + (from: "start", to: "END", cost: 10), + (from: "start", to: "END", cost: 1000), + }; +var map = costs + .Concat(costs.Select(x => (from: x.to, to: x.from, x.cost))) + .Where(x => + x.to != "start" + && x.from != "end") + .ToLookup(x => x.from, x => (x.to, x.cost)); + +// Find the shortest path from start to end +var result = SuperEnumerable + .GetShortestPaths( + "start", + (state, cost) => map[state] + .Select(x => (x.to, x.cost + cost))); + +foreach (var (key, (from, cost)) in result) +{ + Console.WriteLine($"[{key}] = (from: {from}, totalCost: {cost})"); +} + +// This code produces the following output: +// [start] = (from: , totalCost: 0) +// [a] = (from: start, totalCost: 1) +// [b] = (from: a, totalCost: 3) +// [c] = (from: b, totalCost: 6) +// [END] = (from: start, totalCost: 10) +// [d] = (from: c, totalCost: 10) +// [A] = (from: start, totalCost: 10) +// [end] = (from: d, totalCost: 15) +// [B] = (from: A, totalCost: 30) +// [C] = (from: B, totalCost: 60) +// [D] = (from: C, totalCost: 100) diff --git a/Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths2.linq b/Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths2.linq new file mode 100644 index 00000000..90a30dbf --- /dev/null +++ b/Docs/SuperLinq.Docs/apidoc/SuperLinq/GetShortestPaths/GetShortestPaths2.linq @@ -0,0 +1,49 @@ + + SuperLinq + SuperLinq + + +var costs = + new[] + { + (from: "start", to: "a", cost: 1), + (from: "a", to: "b", cost: 2), + (from: "b", to: "c", cost: 3), + (from: "c", to: "d", cost: 4), + (from: "d", to: "end", cost: 5), + (from: "start", to: "A", cost: 10), + (from: "A", to: "B", cost: 20), + (from: "B", to: "C", cost: 30), + (from: "C", to: "D", cost: 40), + (from: "D", to: "end", cost: 50), + (from: "start", to: "END", cost: 10), + (from: "start", to: "END", cost: 1000), + }; +var map = costs + .Concat(costs.Select(x => (from: x.to, to: x.from, x.cost))) + .Where(x => + x.to != "start" + && x.from != "end") + .ToLookup(x => x.from, x => (x.to, x.cost)); + +// Find the shortest path from start to end +var result = SuperEnumerable + .GetShortestPaths( + "start", + (state, cost) => map[state] + .Select(x => (x.to, x.cost + cost)), + StringComparer.OrdinalIgnoreCase, + default); + +foreach (var (key, (from, cost)) in result) +{ + Console.WriteLine($"[{key}] = (from: {from}, totalCost: {cost})"); +} + +// This code produces the following output: +// [start] = (from: , totalCost: 0) +// [a] = (from: start, totalCost: 1) +// [b] = (from: a, totalCost: 3) +// [c] = (from: b, totalCost: 6) +// [END] = (from: start, totalCost: 10) +// [d] = (from: c, totalCost: 10) diff --git a/Source/SuperLinq/GetShortestPaths.cs b/Source/SuperLinq/GetShortestPaths.cs index 0e8c26d3..4e678dca 100644 --- a/Source/SuperLinq/GetShortestPaths.cs +++ b/Source/SuperLinq/GetShortestPaths.cs @@ -5,64 +5,60 @@ namespace SuperLinq; public partial class SuperEnumerable { /// - /// Find the shortest path from state - /// to every other in the map, - /// using Dijkstra's algorithm. + /// Find the shortest path from state to every other in + /// the map, using Dijkstra's algorithm. /// - /// The type of each state in the map - /// The type of the cost to traverse between states - /// The starting state + /// + /// The type of each state in the map + /// + /// + /// The type of the cost to traverse between states + /// + /// + /// The starting state + /// /// - /// A function that returns the neighbors for a given state - /// and the total cost to get to that state based on the - /// traversal cost at the current state. + /// A function that returns the neighbors for a given state and the total cost to get to that state based on the + /// traversal cost at the current state. /// /// - /// A map that contains, for every , - /// the previous in the shortest path - /// from to this , - /// as well as the total cost to travel from - /// to this . + /// A map that contains, for every , the previous in + /// the shortest path from to this , as well as the total + /// cost to travel from to this . /// - /// is . + /// + /// is . + /// /// /// - /// This method uses Dijkstra's algorithm to explore a map - /// and find the shortest path from - /// to every other in the map. - /// An - /// is used to manage the list of s - /// to process, to reduce the computation cost of this operator. + /// This method uses Dijkstra's algorithm to explore a map and find the shortest path from to every other in the map. An is used to manage the list of s to process, to reduce the computation cost of this operator. /// /// - /// Loops and cycles are automatically detected and handled - /// correctly by this operator; only the cheapest path to - /// a given is used, and other - /// paths (including loops) are discarded. + /// Loops and cycles are automatically detected and handled correctly by this operator; only the cheapest path + /// to a given is used, and other paths (including loops) are discarded. /// /// - /// While - /// and - /// will work work on infinite maps, this method - /// will execute an infinite loop on infinite maps. This is because - /// this method will attemp to visit every point in the map. - /// This method will terminate only when any points returned by - /// have all already been visited. + /// While and will work work on infinite maps, + /// this method will execute an infinite loop on infinite maps. This is because this method will attempt to + /// visit every point in the map. This method will terminate only when any points returned by have all already been visited. /// /// - /// Dijkstra's algorithm assumes that all costs are positive, - /// that is to say, that it is not possible to go a negative - /// distance from one state to the next. Violating this assumption - /// will have undefined behavior. + /// Dijkstra's algorithm assumes that all costs are positive, that is to say, that it is not possible to go a + /// negative distance from one state to the next. Violating this assumption will have undefined behavior. /// /// - /// This method uses - /// to compare s and - /// to compare traversal + /// This method uses to compare s and + /// to compare traversal /// s. /// /// - /// This operator executes immediately. + /// This operator executes immediately. /// /// public static IReadOnlyDictionary @@ -80,60 +76,61 @@ public partial class SuperEnumerable } /// - /// Find the shortest path from state - /// to every other in the map, - /// using Dijkstra's algorithm. + /// Find the shortest path from state to every other in + /// the map, using Dijkstra's algorithm. /// - /// The type of each state in the map - /// The type of the cost to traverse between states - /// The starting state + /// + /// The type of each state in the map + /// + /// + /// The type of the cost to traverse between states + /// + /// + /// The starting state + /// /// - /// A function that returns the neighbors for a given state - /// and the total cost to get to that state based on the - /// traversal cost at the current state. + /// A function that returns the neighbors for a given state and the total cost to get to that state based on the + /// traversal cost at the current state. + /// + /// + /// A custom equality comparer for /// - /// A custom equality comparer for - /// A custom comparer for + /// + /// A custom comparer for + /// /// - /// A map that contains, for every , - /// the previous in the shortest path - /// from to this , - /// as well as the total cost to travel from - /// to this . + /// A map that contains, for every , the previous in + /// the shortest path from to this , as well as the total + /// cost to travel from to this . /// - /// is . + /// + /// is . + /// /// /// - /// This method uses Dijkstra's algorithm to explore a map - /// and find the shortest path from - /// to every other in the map. - /// An - /// is used to manage the list of s - /// to process, to reduce the computation cost of this operator. + /// This method uses Dijkstra's algorithm to explore a map and find the shortest path from to every other in the map. An is used to manage the list of s to process, to reduce the computation cost of this operator. /// /// - /// Loops and cycles are automatically detected and handled - /// correctly by this operator; only the cheapest path to - /// a given is used, and other - /// paths (including loops) are discarded. + /// Loops and cycles are automatically detected and handled correctly by this operator; only the cheapest path + /// to a given is used, and other paths (including loops) are discarded. /// /// - /// While - /// and - /// will work work on infinite maps, this method - /// will execute an infinite loop on infinite maps. This is because - /// this method will attemp to visit every point in the map. - /// This method will terminate only when any points returned by - /// have all already been visited. + /// While and will work work on infinite maps, + /// this method will execute an infinite loop on infinite maps. This is because this method will attempt to + /// visit every point in the map. This method will terminate only when any points returned by have all already been visited. /// /// - /// Dijkstra's algorithm assumes that all costs are positive, - /// that is to say, that it is not possible to go a negative - /// distance from one state to the next. Violating this assumption - /// will have undefined behavior. + /// Dijkstra's algorithm assumes that all costs are positive, that is to say, that it is not possible to go a + /// negative distance from one state to the next. Violating this assumption will have undefined behavior. /// /// - /// This operator executes immediately. + /// This operator executes immediately. /// /// public static IReadOnlyDictionary