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