Line data Source code
1 : // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 : // for details. All rights reserved. Use of this source code is governed by a
3 : // BSD-style license that can be found in the LICENSE file.
4 :
5 : import 'dart:math' as math;
6 : import 'dart:collection';
7 :
8 : import 'utils.dart';
9 :
10 : // TODO(nweiz): When sdk#26488 is fixed, use overloads to ensure that if [key]
11 : // or [value] isn't passed, `K2`/`V2` defaults to `K1`/`V1`, respectively.
12 : /// Creates a new map from [map] with new keys and values.
13 : ///
14 : /// The return values of [key] are used as the keys and the return values of
15 : /// [value] are used as the values for the new map.
16 : Map<K2, V2> mapMap<K1, V1, K2, V2>(Map<K1, V1> map,
17 : {K2 key(K1 key, V1 value), V2 value(K1 key, V1 value)}) {
18 : key ??= (mapKey, _) => mapKey as K2;
19 : value ??= (_, mapValue) => mapValue as V2;
20 :
21 0 : var result = <K2, V2>{};
22 0 : map.forEach((mapKey, mapValue) {
23 0 : result[key(mapKey, mapValue)] = value(mapKey, mapValue);
24 : });
25 : return result;
26 : }
27 :
28 : /// Returns a new map with all key/value pairs in both [map1] and [map2].
29 : ///
30 : /// If there are keys that occur in both maps, the [value] function is used to
31 : /// select the value that goes into the resulting map based on the two original
32 : /// values. If [value] is omitted, the value from [map2] is used.
33 : Map<K, V> mergeMaps<K, V>(Map<K, V> map1, Map<K, V> map2,
34 : {V value(V value1, V value2)}) {
35 5 : var result = new Map<K, V>.from(map1);
36 0 : if (value == null) return result..addAll(map2);
37 :
38 5 : map2.forEach((key, mapValue) {
39 0 : result[key] =
40 0 : result.containsKey(key) ? value(result[key], mapValue) : mapValue;
41 : });
42 : return result;
43 : }
44 :
45 : /// Groups the elements in [values] by the value returned by [key].
46 : ///
47 : /// Returns a map from keys computed by [key] to a list of all values for which
48 : /// [key] returns that key. The values appear in the list in the same relative
49 : /// order as in [values].
50 : Map<T, List<S>> groupBy<S, T>(Iterable<S> values, T key(S element)) {
51 0 : var map = <T, List<S>>{};
52 0 : for (var element in values) {
53 0 : var list = map.putIfAbsent(key(element), () => []);
54 0 : list.add(element);
55 : }
56 : return map;
57 : }
58 :
59 : /// Returns the element of [values] for which [orderBy] returns the minimum
60 : /// value.
61 : ///
62 : /// The values returned by [orderBy] are compared using the [compare] function.
63 : /// If [compare] is omitted, values must implement [Comparable<T>] and they are
64 : /// compared using their [Comparable.compareTo].
65 : S minBy<S, T>(Iterable<S> values, T orderBy(S element),
66 : {int compare(T value1, T value2)}) {
67 0 : compare ??= defaultCompare<T>();
68 :
69 : S minValue;
70 : T minOrderBy;
71 0 : for (var element in values) {
72 0 : var elementOrderBy = orderBy(element);
73 0 : if (minOrderBy == null || compare(elementOrderBy, minOrderBy) < 0) {
74 : minValue = element;
75 : minOrderBy = elementOrderBy;
76 : }
77 : }
78 : return minValue;
79 : }
80 :
81 : /// Returns the element of [values] for which [orderBy] returns the maximum
82 : /// value.
83 : ///
84 : /// The values returned by [orderBy] are compared using the [compare] function.
85 : /// If [compare] is omitted, values must implement [Comparable<T>] and they are
86 : /// compared using their [Comparable.compareTo].
87 : S maxBy<S, T>(Iterable<S> values, T orderBy(S element),
88 : {int compare(T value1, T value2)}) {
89 0 : compare ??= defaultCompare<T>();
90 :
91 : S maxValue;
92 : T maxOrderBy;
93 0 : for (var element in values) {
94 0 : var elementOrderBy = orderBy(element);
95 0 : if (maxOrderBy == null || compare(elementOrderBy, maxOrderBy) > 0) {
96 : maxValue = element;
97 : maxOrderBy = elementOrderBy;
98 : }
99 : }
100 : return maxValue;
101 : }
102 :
103 : /// Returns the [transitive closure][] of [graph].
104 : ///
105 : /// [transitive closure]: https://en.wikipedia.org/wiki/Transitive_closure
106 : ///
107 : /// Interprets [graph] as a directed graph with a vertex for each key and edges
108 : /// from each key to the values that the key maps to.
109 : ///
110 : /// Assumes that every vertex in the graph has a key to represent it, even if
111 : /// that vertex has no outgoing edges. This isn't checked, but if it's not
112 : /// satisfied, the function may crash or provide unexpected output. For example,
113 : /// `{"a": ["b"]}` is not valid, but `{"a": ["b"], "b": []}` is.
114 : Map<T, Set<T>> transitiveClosure<T>(Map<T, Iterable<T>> graph) {
115 : // This uses [Warshall's algorithm][], modified not to add a vertex from each
116 : // node to itself.
117 : //
118 : // [Warshall's algorithm]: https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm#Applications_and_generalizations.
119 0 : var result = <T, Set<T>>{};
120 0 : graph.forEach((vertex, edges) {
121 0 : result[vertex] = new Set<T>.from(edges);
122 : });
123 :
124 : // Lists are faster to iterate than maps, so we create a list since we're
125 : // iterating repeatedly.
126 0 : var keys = graph.keys.toList();
127 0 : for (var vertex1 in keys) {
128 0 : for (var vertex2 in keys) {
129 0 : for (var vertex3 in keys) {
130 0 : if (result[vertex2].contains(vertex1) &&
131 0 : result[vertex1].contains(vertex3)) {
132 0 : result[vertex2].add(vertex3);
133 : }
134 : }
135 : }
136 : }
137 :
138 : return result;
139 : }
140 :
141 : /// Returns the [strongly connected components][] of [graph], in topological
142 : /// order.
143 : ///
144 : /// [strongly connected components]: https://en.wikipedia.org/wiki/Strongly_connected_component
145 : ///
146 : /// Interprets [graph] as a directed graph with a vertex for each key and edges
147 : /// from each key to the values that the key maps to.
148 : ///
149 : /// Assumes that every vertex in the graph has a key to represent it, even if
150 : /// that vertex has no outgoing edges. This isn't checked, but if it's not
151 : /// satisfied, the function may crash or provide unexpected output. For example,
152 : /// `{"a": ["b"]}` is not valid, but `{"a": ["b"], "b": []}` is.
153 : List<Set<T>> stronglyConnectedComponents<T>(Map<T, Iterable<T>> graph) {
154 : // This uses [Tarjan's algorithm][].
155 : //
156 : // [Tarjan's algorithm]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
157 : var index = 0;
158 0 : var stack = <T>[];
159 0 : var result = <Set<T>>[];
160 :
161 : // The order of these doesn't matter, so we use un-linked implementations to
162 : // avoid unnecessary overhead.
163 0 : var indices = new HashMap<T, int>();
164 0 : var lowLinks = new HashMap<T, int>();
165 0 : var onStack = new HashSet<T>();
166 :
167 : strongConnect(T vertex) {
168 0 : indices[vertex] = index;
169 0 : lowLinks[vertex] = index;
170 0 : index++;
171 :
172 0 : stack.add(vertex);
173 0 : onStack.add(vertex);
174 :
175 0 : for (var successor in graph[vertex]) {
176 0 : if (!indices.containsKey(successor)) {
177 0 : strongConnect(successor);
178 5 : lowLinks[vertex] = math.min(lowLinks[vertex], lowLinks[successor]);
179 0 : } else if (onStack.contains(successor)) {
180 5 : lowLinks[vertex] = math.min(lowLinks[vertex], lowLinks[successor]);
181 : }
182 : }
183 :
184 0 : if (lowLinks[vertex] == indices[vertex]) {
185 0 : var component = new Set<T>();
186 : T neighbor;
187 : do {
188 0 : neighbor = stack.removeLast();
189 0 : onStack.remove(neighbor);
190 0 : component.add(neighbor);
191 0 : } while (neighbor != vertex);
192 0 : result.add(component);
193 : }
194 : }
195 :
196 0 : for (var vertex in graph.keys) {
197 0 : if (!indices.containsKey(vertex)) strongConnect(vertex);
198 : }
199 :
200 : // Tarjan's algorithm produces a reverse-topological sort, so we reverse it to
201 : // get a normal topological sort.
202 0 : return result.reversed.toList();
203 : }
|