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