LCOV - code coverage report
Current view: top level - collection-1.14.3/lib/src - functions.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 4 56 7.1 %
Date: 2017-10-10 20:17:03 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: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             : }

Generated by: LCOV version 1.13