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

          Line data    Source code
       1             : // Copyright (c) 2020, 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' show Random;
       6             : 
       7             : import 'package:collection/src/utils.dart';
       8             : 
       9             : import 'algorithms.dart';
      10             : 
      11             : /// Extensions that apply to all iterables.
      12             : ///
      13             : /// These extensions provide direct access to some of the
      14             : /// algorithms expose by this package,
      15             : /// as well as some generally useful convenience methods.
      16             : ///
      17             : /// More specialized extension methods that only apply to
      18             : /// iterables with specific element types include those of
      19             : /// [IterableComparableExtension] and [IterableNullableExtension].
      20             : extension IterableExtension<T> on Iterable<T> {
      21             :   /// Selects [count] elements at random from this iterable.
      22             :   ///
      23             :   /// The returned list contains [count] different elements of the iterable.
      24             :   /// If the iterable contains fewer that [count] elements,
      25             :   /// the result will contain all of them, but will be shorter than [count].
      26             :   /// If the same value occurs more than once in the iterable,
      27             :   /// it can also occur more than once in the chosen elements.
      28             :   ///
      29             :   /// Each element of the iterable has the same chance of being chosen.
      30             :   /// The chosen elements are not in any specific order.
      31           0 :   List<T> sample(int count, [Random? random]) {
      32           0 :     RangeError.checkNotNegative(count, 'count');
      33           0 :     var iterator = this.iterator;
      34           0 :     var chosen = <T>[];
      35           0 :     for (var i = 0; i < count; i++) {
      36           0 :       if (iterator.moveNext()) {
      37           0 :         chosen.add(iterator.current);
      38             :       } else {
      39             :         return chosen;
      40             :       }
      41             :     }
      42             :     var index = count;
      43           0 :     random ??= Random();
      44           0 :     while (iterator.moveNext()) {
      45           0 :       index++;
      46           0 :       var position = random.nextInt(index);
      47           0 :       if (position < count) chosen[position] = iterator.current;
      48             :     }
      49             :     return chosen;
      50             :   }
      51             : 
      52             :   /// The elements that do not satisfy [test].
      53           0 :   Iterable<T> whereNot(bool Function(T element) test) =>
      54           0 :       where((element) => !test(element));
      55             : 
      56             :   /// Creates a sorted list of the elements of the iterable.
      57             :   ///
      58             :   /// The elements are ordered by the [compare] [Comparator].
      59           0 :   List<T> sorted(Comparator<T> compare) => [...this]..sort(compare);
      60             : 
      61             :   /// Creates a sorted list of the elements of the iterable.
      62             :   ///
      63             :   /// The elements are ordered by the natural ordering of the
      64             :   /// property [keyOf] of the element.
      65           0 :   List<T> sortedBy<K extends Comparable<K>>(K Function(T element) keyOf) {
      66           0 :     var elements = [...this];
      67           0 :     quickSortBy<T, K>(elements, keyOf, compareComparable);
      68             :     return elements;
      69             :   }
      70             : 
      71             :   /// Creates a sorted list of the elements of the iterable.
      72             :   ///
      73             :   /// The elements are ordered by the [compare] [Comparator] of the
      74             :   /// property [keyOf] of the element.
      75           0 :   List<T> sortedByCompare<K>(
      76             :       K Function(T element) keyOf, Comparator<K> compare) {
      77           0 :     var elements = [...this];
      78           0 :     quickSortBy<T, K>(elements, keyOf, compare);
      79             :     return elements;
      80             :   }
      81             : 
      82             :   /// Whether the elements are sorted by the [compare] ordering.
      83             :   ///
      84             :   /// Compares pairs of elements using `compare` to check that
      85             :   /// the elements of this iterable to check
      86             :   /// that earlier elements always compare
      87             :   /// smaller than or equal to later elements.
      88             :   ///
      89             :   /// An single-element or empty iterable is trivially in sorted order.
      90           0 :   bool isSorted(Comparator<T> compare) {
      91           0 :     var iterator = this.iterator;
      92           0 :     if (!iterator.moveNext()) return true;
      93           0 :     var previousElement = iterator.current;
      94           0 :     while (iterator.moveNext()) {
      95           0 :       var element = iterator.current;
      96           0 :       if (compare(previousElement, element) > 0) return false;
      97             :       previousElement = element;
      98             :     }
      99             :     return true;
     100             :   }
     101             : 
     102             :   /// Whether the elements are sorted by their [keyOf] property.
     103             :   ///
     104             :   /// Applies [keyOf] to each element in iteration order,
     105             :   /// then checks whether the results are in non-decreasing [Comparable] order.
     106           0 :   bool isSortedBy<K extends Comparable<K>>(K Function(T element) keyOf) {
     107           0 :     var iterator = this.iterator;
     108           0 :     if (!iterator.moveNext()) return true;
     109           0 :     var previousKey = keyOf(iterator.current);
     110           0 :     while (iterator.moveNext()) {
     111           0 :       var key = keyOf(iterator.current);
     112           0 :       if (previousKey.compareTo(key) > 0) return false;
     113             :       previousKey = key;
     114             :     }
     115             :     return true;
     116             :   }
     117             : 
     118             :   /// Whether the elements are [compare]-sorted by their [keyOf] property.
     119             :   ///
     120             :   /// Applies [keyOf] to each element in iteration order,
     121             :   /// then checks whether the results are in non-decreasing order
     122             :   /// using the [compare] [Comparator]..
     123           0 :   bool isSortedByCompare<K>(
     124             :       K Function(T element) keyOf, Comparator<K> compare) {
     125           0 :     var iterator = this.iterator;
     126           0 :     if (!iterator.moveNext()) return true;
     127           0 :     var previousKey = keyOf(iterator.current);
     128           0 :     while (iterator.moveNext()) {
     129           0 :       var key = keyOf(iterator.current);
     130           0 :       if (compare(previousKey, key) > 0) return false;
     131             :       previousKey = key;
     132             :     }
     133             :     return true;
     134             :   }
     135             : 
     136             :   /// Takes an action for each element.
     137             :   ///
     138             :   /// Calls [action] for each element along with the index in the
     139             :   /// iteration order.
     140           0 :   void forEachIndexed(void Function(int index, T element) action) {
     141             :     var index = 0;
     142           0 :     for (var element in this) {
     143           0 :       action(index++, element);
     144             :     }
     145             :   }
     146             : 
     147             :   /// Takes an action for each element as long as desired.
     148             :   ///
     149             :   /// Calls [action] for each element.
     150             :   /// Stops iteration if [action] returns `false`.
     151           0 :   void forEachWhile(bool Function(T element) action) {
     152           0 :     for (var element in this) {
     153             :       if (!action(element)) break;
     154             :     }
     155             :   }
     156             : 
     157             :   /// Takes an action for each element and index as long as desired.
     158             :   ///
     159             :   /// Calls [action] for each element along with the index in the
     160             :   /// iteration order.
     161             :   /// Stops iteration if [action] returns `false`.
     162           0 :   void forEachIndexedWhile(bool Function(int index, T element) action) {
     163             :     var index = 0;
     164           0 :     for (var element in this) {
     165           0 :       if (!action(index++, element)) break;
     166             :     }
     167             :   }
     168             : 
     169             :   /// Maps each element and its index to a new value.
     170             :   Iterable<R> mapIndexed<R>(R Function(int index, T element) convert) sync* {
     171             :     var index = 0;
     172             :     for (var element in this) {
     173             :       yield convert(index++, element);
     174             :     }
     175             :   }
     176             : 
     177             :   /// The elements whose value and index satisfies [test].
     178             :   Iterable<T> whereIndexed(bool Function(int index, T element) test) sync* {
     179             :     var index = 0;
     180             :     for (var element in this) {
     181             :       if (test(index++, element)) yield element;
     182             :     }
     183             :   }
     184             : 
     185             :   /// The elements whose value and index do not satisfy [test].
     186             :   Iterable<T> whereNotIndexed(bool Function(int index, T element) test) sync* {
     187             :     var index = 0;
     188             :     for (var element in this) {
     189             :       if (!test(index++, element)) yield element;
     190             :     }
     191             :   }
     192             : 
     193             :   /// Expands each element and index to a number of elements in a new iterable.
     194             :   Iterable<R> expandIndexed<R>(
     195             :       Iterable<R> Function(int index, T element) expend) sync* {
     196             :     var index = 0;
     197             :     for (var element in this) {
     198             :       yield* expend(index++, element);
     199             :     }
     200             :   }
     201             : 
     202             :   /// Combine the elements with each other and the current index.
     203             :   ///
     204             :   /// Calls [combine] for each element except the first.
     205             :   /// The call passes the index of the current element, the result of the
     206             :   /// previous call, or the first element for the first call, and
     207             :   /// the current element.
     208             :   ///
     209             :   /// Returns the result of the last call, or the first element if
     210             :   /// there is only one element.
     211             :   /// There must be at least one element.
     212           0 :   T reduceIndexed(T Function(int index, T previous, T element) combine) {
     213           0 :     var iterator = this.iterator;
     214           0 :     if (!iterator.moveNext()) {
     215           0 :       throw StateError('no elements');
     216             :     }
     217             :     var index = 1;
     218           0 :     var result = iterator.current;
     219           0 :     while (iterator.moveNext()) {
     220           0 :       result = combine(index++, result, iterator.current);
     221             :     }
     222             :     return result;
     223             :   }
     224             : 
     225             :   /// Combine the elements with a value and the current index.
     226             :   ///
     227             :   /// Calls [combine] for each element with the current index,
     228             :   /// the result of the previous call, or [initialValue] for the first element,
     229             :   /// and the current element.
     230             :   ///
     231             :   /// Returns the result of the last call to [combine],
     232             :   /// or [initialValue] if there are no elements.
     233           0 :   R foldIndexed<R>(
     234             :       R initialValue, R Function(int index, R previous, T element) combine) {
     235             :     var result = initialValue;
     236             :     var index = 0;
     237           0 :     for (var element in this) {
     238           0 :       result = combine(index++, result, element);
     239             :     }
     240             :     return result;
     241             :   }
     242             : 
     243             :   /// The first element satisfying [test], or `null` if there are none.
     244           0 :   T? firstWhereOrNull(bool Function(T element) test) {
     245           0 :     for (var element in this) {
     246             :       if (test(element)) return element;
     247             :     }
     248             :     return null;
     249             :   }
     250             : 
     251             :   /// The first element whose value and index satisfies [test].
     252             :   ///
     253             :   /// Returns `null` if there are no element and index satisfying [test].
     254           0 :   T? firstWhereIndexedOrNull(bool Function(int index, T element) test) {
     255             :     var index = 0;
     256           0 :     for (var element in this) {
     257           0 :       if (test(index++, element)) return element;
     258             :     }
     259             :     return null;
     260             :   }
     261             : 
     262             :   /// The first element, or `null` if the iterable is empty.
     263           0 :   T? get firstOrNull {
     264           0 :     var iterator = this.iterator;
     265           0 :     if (iterator.moveNext()) return iterator.current;
     266             :     return null;
     267             :   }
     268             : 
     269             :   /// The last element satisfying [test], or `null` if there are none.
     270           0 :   T? lastWhereOrNull(bool Function(T element) test) {
     271             :     T? result;
     272           0 :     for (var element in this) {
     273             :       if (test(element)) result = element;
     274             :     }
     275             :     return result;
     276             :   }
     277             : 
     278             :   /// The last element whose index and value satisfies [test].
     279             :   ///
     280             :   /// Returns `null` if no element and index satisfies [test].
     281           0 :   T? lastWhereIndexedOrNull(bool Function(int index, T element) test) {
     282             :     T? result;
     283             :     var index = 0;
     284           0 :     for (var element in this) {
     285           0 :       if (test(index++, element)) result = element;
     286             :     }
     287             :     return result;
     288             :   }
     289             : 
     290             :   /// The last element, or `null` if the iterable is empty.
     291           0 :   T? get lastOrNull {
     292           0 :     if (isEmpty) return null;
     293           0 :     return last;
     294             :   }
     295             : 
     296             :   /// The single element satisfying [test].
     297             :   ///
     298             :   /// Returns `null` if there are either no elements
     299             :   /// or more than one element satisfying [test].
     300             :   ///
     301             :   /// **Notice**: This behavior differs from [Iterable.singleWhere]
     302             :   /// which always throws if there are more than one match,
     303             :   /// and only calls the `orElse` function on zero matchs.
     304           0 :   T? singleWhereOrNull(bool Function(T element) test) {
     305             :     T? result;
     306             :     var found = false;
     307           0 :     for (var element in this) {
     308             :       if (test(element)) {
     309             :         if (!found) {
     310             :           result = element;
     311             :           found = true;
     312             :         } else {
     313             :           return null;
     314             :         }
     315             :       }
     316             :     }
     317             :     return result;
     318             :   }
     319             : 
     320             :   /// The single element satisfying [test].
     321             :   ///
     322             :   /// Returns `null` if there are either none
     323             :   /// or more than one element and index satisfying [test].
     324           0 :   T? singleWhereIndexedOrNull(bool Function(int index, T element) test) {
     325             :     T? result;
     326             :     var found = false;
     327             :     var index = 0;
     328           0 :     for (var element in this) {
     329           0 :       if (test(index++, element)) {
     330             :         if (!found) {
     331             :           result = element;
     332             :           found = true;
     333             :         } else {
     334             :           return null;
     335             :         }
     336             :       }
     337             :     }
     338             :     return result;
     339             :   }
     340             : 
     341             :   /// The single element of the iterable, or `null`.
     342             :   ///
     343             :   /// The value is `null` if the iterable is empty
     344             :   /// or it contains more than one element.
     345           0 :   T? get singleOrNull {
     346           0 :     var iterator = this.iterator;
     347           0 :     if (iterator.moveNext()) {
     348           0 :       var result = iterator.current;
     349           0 :       if (!iterator.moveNext()) {
     350             :         return result;
     351             :       }
     352             :     }
     353             :     return null;
     354             :   }
     355             : 
     356             :   /// Groups elements by [keyOf] then folds the elements in each group.
     357             :   ///
     358             :   /// A key is found for each element using [keyOf].
     359             :   /// Then the elements with the same key are all folded using [combine].
     360             :   /// The first call to [combine] for a particular key receives [null] as
     361             :   /// the previous value, the remaining ones receive the result of the previous call.
     362             :   ///
     363             :   /// Can be used to _group_ elements into arbitrary collections.
     364             :   /// For example [groupSetsBy] could be written as:
     365             :   /// ```dart
     366             :   /// iterable.groupFoldBy(keyOf,
     367             :   ///     (Set<T>? previous, T element) => (previous ?? <T>{})..add(element));
     368             :   /// ````
     369           0 :   Map<K, G> groupFoldBy<K, G>(
     370             :       K Function(T element) keyOf, G Function(G? previous, T element) combine) {
     371           0 :     var result = <K, G>{};
     372           0 :     for (var element in this) {
     373             :       var key = keyOf(element);
     374           0 :       result[key] = combine(result[key], element);
     375             :     }
     376             :     return result;
     377             :   }
     378             : 
     379             :   /// Groups elements into sets by [keyOf].
     380           0 :   Map<K, Set<T>> groupSetsBy<K>(K Function(T element) keyOf) {
     381           0 :     var result = <K, Set<T>>{};
     382           0 :     for (var element in this) {
     383           0 :       (result[keyOf(element)] ??= <T>{})..add(element);
     384             :     }
     385             :     return result;
     386             :   }
     387             : 
     388             :   /// Groups elements into lists by [keyOf].
     389           0 :   Map<K, List<T>> groupListsBy<K>(K Function(T element) keyOf) {
     390           0 :     var result = <K, List<T>>{};
     391           0 :     for (var element in this) {
     392           0 :       (result[keyOf(element)] ??= [])..add(element);
     393             :     }
     394             :     return result;
     395             :   }
     396             : 
     397             :   /// Splits the elements into chunks before some elements.
     398             :   ///
     399             :   /// Each element except the first is checked using [test]
     400             :   /// for whether it should start a new chunk.
     401             :   /// If so, the elements since the previous chunk-starting element
     402             :   /// are emitted as a list.
     403             :   /// Any final elements are emitted at the end.
     404             :   ///
     405             :   /// Example:
     406             :   /// Example:
     407             :   /// ```dart
     408             :   /// var parts = [1, 2, 3, 4, 5, 6, 7, 8, 9].split(isPrime);
     409             :   /// print(parts); // ([1], [2], [3, 4], [5, 6], [7, 8, 9])
     410             :   /// ```
     411           0 :   Iterable<List<T>> splitBefore(bool Function(T element) test) =>
     412           0 :       splitBeforeIndexed((_, element) => test(element));
     413             : 
     414             :   /// Splits the elements into chunks before some elements.
     415             :   ///
     416             :   /// Each element is checked using [test] for whether it should start a new chunk.
     417             :   /// If so, the elements since the previous chunk-starting element
     418             :   /// are emitted as a list.
     419             :   /// Any final elements are emitted at the end.
     420             :   ///
     421             :   /// Example:
     422             :   /// ```dart
     423             :   /// var parts = [1, 0, 2, 1, 5, 7, 6, 8, 9].splitAfter(isPrime);
     424             :   /// print(parts); // ([1, 0, 2], [1, 5], [7], [6, 8, 9])
     425             :   /// ```
     426           0 :   Iterable<List<T>> splitAfter(bool Function(T element) test) =>
     427           0 :       splitAfterIndexed((_, element) => test(element));
     428             : 
     429             :   /// Splits the elements into chunks between some elements.
     430             :   ///
     431             :   /// Each pair of adjacent elements are checked using [test]
     432             :   /// for whether a chunk should end between them.
     433             :   /// If so, the elements since the previous chunk-splitting elements
     434             :   /// are emitted as a list.
     435             :   /// Any final elements are emitted at the end.
     436             :   ///
     437             :   /// Example:
     438             :   /// ```dart
     439             :   /// var parts = [1, 0, 2, 1, 5, 7, 6, 8, 9].splitBetween((i, v1, v2) => v1 > v2);
     440             :   /// print(parts); // ([1], [0, 2], [1, 5, 7], [6, 8, 9])
     441             :   /// ```
     442           0 :   Iterable<List<T>> splitBetween(bool Function(T first, T second) test) =>
     443           0 :       splitBetweenIndexed((_, first, second) => test(first, second));
     444             : 
     445             :   /// Splits the elements into chunks before some elements and indices.
     446             :   ///
     447             :   /// Each element and index except the first is checked using [test]
     448             :   /// for whether it should start a new chunk.
     449             :   /// If so, the elements since the previous chunk-starting element
     450             :   /// are emitted as a list.
     451             :   /// Any final elements are emitted at the end.
     452             :   ///
     453             :   /// Example:
     454             :   /// ```dart
     455             :   /// var parts = [1, 0, 2, 1, 5, 7, 6, 8, 9]
     456             :   ///     .splitBeforeIndexed((i, v) => i < v);
     457             :   /// print(parts); // ([1], [0, 2], [1, 5, 7], [6, 8, 9])
     458             :   /// ```
     459             :   Iterable<List<T>> splitBeforeIndexed(
     460             :       bool Function(int index, T element) test) sync* {
     461             :     var iterator = this.iterator;
     462             :     if (!iterator.moveNext()) {
     463             :       return;
     464             :     }
     465             :     var index = 1;
     466             :     var chunk = [iterator.current];
     467             :     while (iterator.moveNext()) {
     468             :       var element = iterator.current;
     469             :       if (test(index++, element)) {
     470             :         yield chunk;
     471             :         chunk = [];
     472             :       }
     473             :       chunk.add(element);
     474             :     }
     475             :     yield chunk;
     476             :   }
     477             : 
     478             :   /// Splits the elements into chunks after some elements and indices.
     479             :   ///
     480             :   /// Each element and index is checked using [test]
     481             :   /// for whether it should end the current chunk.
     482             :   /// If so, the elements since the previous chunk-ending element
     483             :   /// are emitted as a list.
     484             :   /// Any final elements are emitted at the end, whether the last
     485             :   /// element should be split after or not.
     486             :   ///
     487             :   /// Example:
     488             :   /// ```dart
     489             :   /// var parts = [1, 0, 2, 1, 5, 7, 6, 8, 9].splitAfterIndexed((i, v) => i < v);
     490             :   /// print(parts); // ([1, 0], [2, 1], [5, 7, 6], [8, 9])
     491             :   /// ```
     492             :   Iterable<List<T>> splitAfterIndexed(
     493             :       bool Function(int index, T element) test) sync* {
     494             :     var index = 0;
     495             :     List<T>? chunk;
     496             :     for (var element in this) {
     497             :       (chunk ??= []).add(element);
     498             :       if (test(index++, element)) {
     499             :         yield chunk;
     500             :         chunk = null;
     501             :       }
     502             :     }
     503             :     if (chunk != null) yield chunk;
     504             :   }
     505             : 
     506             :   /// Splits the elements into chunks between some elements and indices.
     507             :   ///
     508             :   /// Each pair of adjacent elements and the index of the latter are
     509             :   /// checked using [test] for whether a chunk should end between them.
     510             :   /// If so, the elements since the previous chunk-splitting elements
     511             :   /// are emitted as a list.
     512             :   /// Any final elements are emitted at the end.
     513             :   ///
     514             :   /// Example:
     515             :   /// ```dart
     516             :   /// var parts = [1, 0, 2, 1, 5, 7, 6, 8, 9]
     517             :   ///    .splitBetweenIndexed((i, v1, v2) => v1 > v2);
     518             :   /// print(parts); // ([1], [0, 2], [1, 5, 7], [6, 8, 9])
     519             :   /// ```
     520             :   Iterable<List<T>> splitBetweenIndexed(
     521             :       bool Function(int index, T first, T second) test) sync* {
     522             :     var iterator = this.iterator;
     523             :     if (!iterator.moveNext()) return;
     524             :     var previous = iterator.current;
     525             :     var chunk = <T>[previous];
     526             :     var index = 1;
     527             :     while (iterator.moveNext()) {
     528             :       var element = iterator.current;
     529             :       if (test(index++, previous, element)) {
     530             :         yield chunk;
     531             :         chunk = [];
     532             :       }
     533             :       chunk.add(element);
     534             :       previous = element;
     535             :     }
     536             :     yield chunk;
     537             :   }
     538             : 
     539             :   /// Whether no element satisfies [test].
     540             :   ///
     541             :   /// Returns true if no element satisfies [test],
     542             :   /// and false if at least one does.
     543             :   ///
     544             :   /// Equivalent to `iterable.every((x) => !test(x))` or
     545             :   /// `!iterable.any(test)`.
     546           0 :   bool none(bool Function(T) test) {
     547           0 :     for (var element in this) {
     548             :       if (test(element)) return false;
     549             :     }
     550             :     return true;
     551             :   }
     552             : }
     553             : 
     554             : /// Extensions that apply to iterables with a nullable element type.
     555             : extension IterableNullableExtension<T extends Object> on Iterable<T?> {
     556             :   /// The non-`null` elements of this `Iterable`.
     557             :   ///
     558             :   /// Returns an iterable which emits all the non-`null` elements
     559             :   /// of this iterable, in their original iteration order.
     560             :   ///
     561             :   /// For an `Iterable<X?>`, this method is equivalent to `.whereType<X>()`.
     562             :   Iterable<T> whereNotNull() sync* {
     563             :     for (var element in this) {
     564             :       if (element != null) yield element;
     565             :     }
     566             :   }
     567             : }
     568             : 
     569             : /// Extensions that apply to iterables of numbers.
     570             : extension IterableNumberExtension on Iterable<num> {
     571             :   /// The sum of the elements.
     572             :   ///
     573             :   /// The sum is zero if the iterable is empty.
     574           0 :   num get sum {
     575             :     num result = 0;
     576           0 :     for (var value in this) {
     577           0 :       result += value;
     578             :     }
     579             :     return result;
     580             :   }
     581             : 
     582             :   /// The arithmetic mean of the elements of a non-empty iterable.
     583             :   ///
     584             :   /// The arithmetic mean is the sum of the elements
     585             :   /// divided by the number of elements.
     586             :   ///
     587             :   /// The iterable must not be empty.
     588           0 :   double get average {
     589             :     var result = 0.0;
     590             :     var count = 0;
     591           0 :     for (var value in this) {
     592           0 :       count += 1;
     593           0 :       result += (value - result) / count;
     594             :     }
     595           0 :     if (count == 0) throw StateError('No elements');
     596             :     return result;
     597             :   }
     598             : }
     599             : 
     600             : /// Extension on iterables of integers.
     601             : ///
     602             : /// Specialized version of some extensions of [IterableNumberExtension].
     603             : extension IterableIntegerExtension on Iterable<int> {
     604             :   /// The sum of the elements.
     605             :   ///
     606             :   /// The sum is zero if the iterable is empty.
     607           0 :   int get sum {
     608             :     var result = 0;
     609           0 :     for (var value in this) {
     610           0 :       result += value;
     611             :     }
     612             :     return result;
     613             :   }
     614             : 
     615             :   /// The arithmetic mean of the elements of a non-empty iterable.
     616             :   ///
     617             :   /// The arithmetic mean is the sum of the elements
     618             :   /// divided by the number of elements.
     619             :   /// This method is specialized for integers,
     620             :   /// and may give a different result than [IterableNumberExtension.average]
     621             :   /// for the same values, because the the number algorithm
     622             :   /// converts all numbers to doubles.
     623             :   ///
     624             :   /// The iterable must not be empty.
     625           0 :   double get average {
     626             :     var average = 0;
     627             :     var remainder = 0;
     628             :     var count = 0;
     629           0 :     for (var value in this) {
     630             :       // Invariant: Sum of values so far = average * count + remainder.
     631             :       // (Unless overflow has occurred).
     632           0 :       count += 1;
     633           0 :       var delta = value - average + remainder;
     634           0 :       average += delta ~/ count;
     635           0 :       remainder = delta.remainder(count);
     636             :     }
     637           0 :     if (count == 0) throw StateError('No elements');
     638           0 :     return average + remainder / count;
     639             :   }
     640             : }
     641             : 
     642             : /// Extension on iterables of double.
     643             : ///
     644             : /// Specialized version of some extensions of [IterableNumberExtension].
     645             : extension IterableDoubleExtension on Iterable<double> {
     646             :   /// The sum of the elements.
     647             :   ///
     648             :   /// The sum is zero if the iterable is empty.
     649           0 :   double get sum {
     650             :     var result = 0.0;
     651           0 :     for (var value in this) {
     652           0 :       result += value;
     653             :     }
     654             :     return result;
     655             :   }
     656             : }
     657             : 
     658             : /// Extensions on iterables whose elements are also iterables.
     659             : extension IterableIterableExtension<T> on Iterable<Iterable<T>> {
     660             :   /// The sequential elements of each iterable in this iterable.
     661             :   ///
     662             :   /// Iterates the elements of this iterable.
     663             :   /// For each one, which is itself an iterable,
     664             :   /// all the elements of that are emitted
     665             :   /// on the returned iterable, before moving on to the next element.
     666             :   Iterable<T> get flattened sync* {
     667             :     for (var elements in this) {
     668             :       yield* elements;
     669             :     }
     670             :   }
     671             : }
     672             : 
     673             : /// Extensions that apply to iterables of [Comparable] elements.
     674             : ///
     675             : /// These operations can assume that the elements have a natural ordering,
     676             : /// and can therefore omit, or make it optional, for the user to provide
     677             : /// a [Comparator].
     678             : extension IterableComparableExtension<T extends Comparable<T>> on Iterable<T> {
     679             :   /// A minimal element of the iterable, or `null` it the iterable is empty.
     680           0 :   T? get minOrNull {
     681           0 :     var iterator = this.iterator;
     682           0 :     if (iterator.moveNext()) {
     683           0 :       var value = iterator.current;
     684           0 :       while (iterator.moveNext()) {
     685           0 :         var newValue = iterator.current;
     686           0 :         if (value.compareTo(newValue) > 0) {
     687             :           value = newValue;
     688             :         }
     689             :       }
     690             :       return value;
     691             :     }
     692             :     return null;
     693             :   }
     694             : 
     695             :   /// A minimal element of the iterable.
     696             :   ///
     697             :   /// The iterable must not be empty.
     698           0 :   T get min {
     699           0 :     var iterator = this.iterator;
     700           0 :     if (iterator.moveNext()) {
     701           0 :       var value = iterator.current;
     702           0 :       while (iterator.moveNext()) {
     703           0 :         var newValue = iterator.current;
     704           0 :         if (value.compareTo(newValue) > 0) {
     705             :           value = newValue;
     706             :         }
     707             :       }
     708             :       return value;
     709             :     }
     710           0 :     throw StateError('No element');
     711             :   }
     712             : 
     713             :   /// A maximal element of the iterable, or `null` if the iterable is empty.
     714           0 :   T? get maxOrNull {
     715           0 :     var iterator = this.iterator;
     716           0 :     if (iterator.moveNext()) {
     717           0 :       var value = iterator.current;
     718           0 :       while (iterator.moveNext()) {
     719           0 :         var newValue = iterator.current;
     720           0 :         if (value.compareTo(newValue) < 0) {
     721             :           value = newValue;
     722             :         }
     723             :       }
     724             :       return value;
     725             :     }
     726             :     return null;
     727             :   }
     728             : 
     729             :   /// A maximal element of the iterable.
     730             :   ///
     731             :   /// The iterable must not be empty.
     732           0 :   T get max {
     733           0 :     var iterator = this.iterator;
     734           0 :     if (iterator.moveNext()) {
     735           0 :       var value = iterator.current;
     736           0 :       while (iterator.moveNext()) {
     737           0 :         var newValue = iterator.current;
     738           0 :         if (value.compareTo(newValue) < 0) {
     739             :           value = newValue;
     740             :         }
     741             :       }
     742             :       return value;
     743             :     }
     744           0 :     throw StateError('No element');
     745             :   }
     746             : 
     747             :   /// Creates a sorted list of the elements of the iterable.
     748             :   ///
     749             :   /// If the [compare] function is not supplied, the sorting uses the
     750             :   /// natural [Comparable] ordering of the elements.
     751           0 :   List<T> sorted([Comparator<T>? compare]) => [...this]..sort(compare);
     752             : 
     753             :   /// Whether the elements are sorted by the [compare] ordering.
     754             :   ///
     755             :   /// If [compare] is omitted, it defaults to comparing the
     756             :   /// elements using their natural [Comparable] ordering.
     757           0 :   bool isSorted([Comparator<T>? compare]) {
     758             :     if (compare != null) {
     759           0 :       return IterableExtension(this).isSorted(compare);
     760             :     }
     761           0 :     var iterator = this.iterator;
     762           0 :     if (!iterator.moveNext()) return true;
     763           0 :     var previousElement = iterator.current;
     764           0 :     while (iterator.moveNext()) {
     765           0 :       var element = iterator.current;
     766           0 :       if (previousElement.compareTo(element) > 0) return false;
     767             :       previousElement = element;
     768             :     }
     769             :     return true;
     770             :   }
     771             : }
     772             : 
     773             : /// Extensions on comparator functions.
     774             : extension ComparatorExtension<T> on Comparator<T> {
     775             :   /// The inverse ordering of this comparator.
     776           0 :   Comparator<T> get inverse => (T a, T b) => this(b, a);
     777             : 
     778             :   /// Makes a comparator on [R] values using this comparator.
     779             :   ///
     780             :   /// Compares [R] values by comparing their [keyOf] value
     781             :   /// using this comparator.
     782           0 :   Comparator<R> compareBy<R>(T Function(R) keyOf) =>
     783           0 :       (R a, R b) => this(keyOf(a), keyOf(b));
     784             : 
     785             :   /// Combine comparators sequentially.
     786             :   ///
     787             :   /// Creates a comparator which orders elements the same way as
     788             :   /// this comparator, except that when two elements are considered
     789             :   /// equal, the [tieBreaker] comparator is used instead.
     790           0 :   Comparator<T> then(Comparator<T> tieBreaker) => (T a, T b) {
     791             :         var result = this(a, b);
     792           0 :         if (result == 0) result = tieBreaker(a, b);
     793             :         return result;
     794             :       };
     795             : }

Generated by: LCOV version 1.14