LCOV - code coverage report
Current view: top level - collection-1.15.0/lib/src - functions.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 3 59 5.1 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          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             : }

Generated by: LCOV version 1.14