Documentation update for Iterable class
Contains:
- Examples
Closes https://github.com/dart-lang/sdk/pull/47845
https://github.com/dart-lang/sdk/pull/47845
GitOrigin-RevId: ba3b885224b2511be2b06148d16bd6d3622473d9
Change-Id: Iadc197183b6464d66527701ba71978c8d9ac683a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/222023
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 0b42ab7..41d7e23 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -162,6 +162,13 @@
/// The returned iterable will provide the same elements as this iterable,
/// and, after that, the elements of [other], in the same order as in the
/// original iterables.
+ ///
+ /// Example:
+ /// ```dart
+ /// var planets = <String>['Earth', 'Jupiter'];
+ /// var updated = planets.followedBy(['Mars', 'Venus']);
+ /// print(updated); // (Earth, Jupiter, Mars, Venus)
+ /// ```
Iterable<E> followedBy(Iterable<E> other) {
var self = this; // TODO(lrn): Remove when we can promote `this`.
if (self is EfficientLengthIterable<E>) {
@@ -189,13 +196,24 @@
/// For example, [elementAt] may call `toElement` only once.
///
/// Equivalent to:
- /// ```dart
+ /// ```
/// Iterable<T> map<T>(T toElement(E e)) sync* {
/// for (var value in this) {
/// yield toElement(value);
/// }
/// }
/// ```
+ /// Example:
+ /// ```dart import:convert
+ /// var products = jsonDecode('''
+ /// [
+ /// {"name": "Screwdriver", "price": 42.00},
+ /// {"name": "Wingnut", "price": 0.50}
+ /// ]
+ /// ''');
+ /// var values = products.map((product) => product['price'] as double);
+ /// var totalPrice = values.fold(0.0, (a, b) => a + b); // 42.5.
+ /// ```
Iterable<T> map<T>(T toElement(E e)) => MappedIterable<E, T>(this, toElement);
/// Returns a new lazy [Iterable] with all elements that satisfy the
@@ -210,6 +228,14 @@
/// Iterating will not cache results, and thus iterating multiple times over
/// the returned [Iterable] may invoke the supplied
/// function [test] multiple times on the same element.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.where((x) => x < 5); // (1, 2, 3)
+ /// result = numbers.where((x) => x > 5); // (6, 7)
+ /// result = numbers.where((x) => x.isEven); // (2, 6)
+ /// ```
Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
/// Returns a new lazy [Iterable] with all elements that have type [T].
@@ -233,17 +259,18 @@
///
/// Example:
/// ```dart
- /// var pairs = [[1, 2], [3, 4]];
- /// var flattened = pairs.expand((pair) => pair).toList();
- /// print(flattened); // => [1, 2, 3, 4];
+ /// Iterable<int> count(int n) sync* {
+ /// for (var i = 1; i <= n; i++) {
+ /// yield i;
+ /// }
+ /// }
///
- /// var input = [1, 2, 3];
- /// var duplicated = input.expand((i) => [i, i]).toList();
- /// print(duplicated); // => [1, 1, 2, 2, 3, 3]
+ /// var numbers = [1, 3, 0, 2];
+ /// print(numbers.expand(count)); // (1, 1, 2, 3, 1, 2)
/// ```
///
/// Equivalent to:
- /// ```dart
+ /// ```
/// Iterable<T> expand<T>(Iterable<T> toElements(E e)) sync* {
/// for (var value in this) {
/// yield* toElements(value);
@@ -267,6 +294,15 @@
/// (see [Set.identity]) that its `contains` uses.
/// Likewise the `Iterable` returned by a [Map.keys] call
/// should use the same equality that the `Map` uses for keys.
+ ///
+ /// Example:
+ /// ```dart
+ /// final gasPlanets = <int, String>{1: 'Jupiter', 2: 'Saturn'};
+ /// final containsOne = gasPlanets.keys.contains(1); // true
+ /// final containsFive = gasPlanets.keys.contains(5); // false
+ /// final containsJupiter = gasPlanets.values.contains('Jupiter'); // true
+ /// final containsMercury = gasPlanets.values.contains('Mercury'); // false
+ /// ```
bool contains(Object? element) {
for (E e in this) {
if (e == element) return true;
@@ -275,6 +311,16 @@
}
/// Invokes [action] on each element of this iterable in iteration order.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 6, 7];
+ /// numbers.forEach(print);
+ /// // 1
+ /// // 2
+ /// // 6
+ /// // 7
+ /// ```
void forEach(void action(E element)) {
for (E element in this) action(element);
}
@@ -288,7 +334,7 @@
/// Otherwise this method starts with the first element from the iterator,
/// and then combines it with the remaining elements in iteration order,
/// as if by:
- /// ```dart
+ /// ```
/// E value = iterable.first;
/// iterable.skip(1).forEach((element) {
/// value = combine(value, element);
@@ -297,7 +343,9 @@
/// ```
/// Example of calculating the sum of an iterable:
/// ```dart
- /// iterable.reduce((value, element) => value + element);
+ /// final numbers = <double>[10, 2, 5, 0.5];
+ /// final result = numbers.reduce((value, element) => value + element);
+ /// print(result); // 17.5
/// ```
E reduce(E combine(E value, E element)) {
Iterator<E> iterator = this.iterator;
@@ -317,7 +365,7 @@
/// Uses [initialValue] as the initial value,
/// then iterates through the elements and updates the value with
/// each element using the [combine] function, as if by:
- /// ```dart
+ /// ```
/// var value = initialValue;
/// for (E element in this) {
/// value = combine(value, element);
@@ -326,7 +374,11 @@
/// ```
/// Example of calculating the sum of an iterable:
/// ```dart
- /// iterable.fold(0, (prev, element) => prev + element);
+ /// final numbers = <double>[10, 2, 5, 0.5];
+ /// const initialValue = 100.0;
+ /// final result = numbers.fold<double>(
+ /// initialValue, (previousValue, element) => previousValue + element);
+ /// print(result); // 117.5
/// ```
T fold<T>(T initialValue, T combine(T previousValue, E element)) {
var value = initialValue;
@@ -338,6 +390,14 @@
///
/// Checks every element in iteration order, and returns `false` if
/// any of them make [test] return `false`, otherwise returns `true`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planetsByMass = <double, String>{0.06: 'Mercury', 0.81: 'Venus',
+ /// 0.11: 'Mars'};
+ /// // Checks whether all keys are smaller than 1.
+ /// final every = planetsByMass.keys.every((key) => key < 1.0); // true
+ /// ```
bool every(bool test(E element)) {
for (E element in this) {
if (!test(element)) return false;
@@ -351,6 +411,13 @@
/// converts each one to a [String] by calling [Object.toString],
/// and then concatenates the strings, with the
/// [separator] string interleaved between the elements.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planetsByMass = <double, String>{0.06: 'Mercury', 0.81: 'Venus',
+ /// 0.11: 'Mars'};
+ /// final joinedNames = planetsByMass.values.join('-'); // Mercury-Venus-Mars
+ /// ```
String join([String separator = ""]) {
Iterator<E> iterator = this.iterator;
if (!iterator.moveNext()) return "";
@@ -373,6 +440,13 @@
///
/// Checks every element in iteration order, and returns `true` if
/// any of them make [test] return `true`, otherwise returns false.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.any((element) => element >= 5); // true;
+ /// result = numbers.any((element) => element >= 10); // false;
+ /// ```
bool any(bool test(E element)) {
for (E element in this) {
if (test(element)) return true;
@@ -384,6 +458,14 @@
///
/// The elements are in iteration order.
/// The list is fixed-length if [growable] is false.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Mars'};
+ /// final keysList = planets.keys.toList(growable: false); // [1, 2, 3]
+ /// final valuesList =
+ /// planets.values.toList(growable: false); // [Mercury, Venus, Mars]
+ /// ```
List<E> toList({bool growable = true}) {
return List<E>.of(this, growable: growable);
}
@@ -395,6 +477,12 @@
/// or it contains one or more elements that are equal.
/// The order of the elements in the set is not guaranteed to be the same
/// as for the iterable.
+ ///
+ /// Example:
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Mars'};
+ /// final valueSet = planets.values.toSet(); // {Mercury, Venus, Mars}
+ /// ```
Set<E> toSet() => Set<E>.of(this);
/// Returns the number of elements in [this].
@@ -415,11 +503,25 @@
/// Whether this collection has no elements.
///
/// May be computed by checking if `iterator.moveNext()` returns `false`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final emptyList = <int>[];
+ /// print(emptyList.isEmpty); // true;
+ /// print(emptyList.iterator.moveNext()); // false
+ /// ```
bool get isEmpty => !iterator.moveNext();
/// Whether this collection has at least one element.
///
/// May be computed by checking if `iterator.moveNext()` returns `true`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>{1, 2, 3};
+ /// print(numbers.isNotEmpty); // true;
+ /// print(numbers.iterator.moveNext()); // true
+ /// ```
bool get isNotEmpty => !isEmpty;
/// Returns a lazy iterable of the [count] first elements of this iterable.
@@ -431,6 +533,13 @@
/// elements have been seen.
///
/// The `count` must not be negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// final result = numbers.take(4); // (1, 2, 3, 5)
+ /// final takeAll = numbers.take(100); // (1, 2, 3, 5, 6, 7)
+ /// ```
Iterable<E> take(int count) {
return TakeIterable<E>(this, count);
}
@@ -443,6 +552,15 @@
/// The elements can be computed by stepping through [iterator] until an
/// element is found where `test(element)` is false. At that point,
/// the returned iterable stops (its `moveNext()` returns false).
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.takeWhile((x) => x < 5); // (1, 2, 3)
+ /// result = numbers.takeWhile((x) => x != 3); // (1, 2)
+ /// result = numbers.takeWhile((x) => x != 4); // (1, 2, 3, 5, 6, 7)
+ /// result = numbers.takeWhile((x) => x.isOdd); // (1)
+ /// ```
Iterable<E> takeWhile(bool test(E value)) {
return TakeWhileIterable<E>(this, test);
}
@@ -460,6 +578,13 @@
/// through earlier elements, for example when iterating a [List].
/// Such iterables are allowed to ignore the initial skipped elements.
///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// final result = numbers.skip(4); // (6, 7)
+ /// final skipAll = numbers.skip(100); // () - no elements.
+ /// ```
+ ///
/// The [count] must not be negative.
Iterable<E> skip(int count) {
return SkipIterable<E>(this, count);
@@ -475,6 +600,15 @@
/// true. If all elements satisfy `test` the resulting iterable is empty,
/// otherwise it iterates the remaining elements in their original order,
/// starting with the first element for which `test(element)` returns `false`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.skipWhile((x) => x < 5); // (5, 6, 7)
+ /// result = numbers.skipWhile((x) => x != 3); // (3, 5, 6, 7)
+ /// result = numbers.skipWhile((x) => x != 4); // ()
+ /// result = numbers.skipWhile((x) => x.isOdd); // (2, 3, 5, 6, 7)
+ /// ```
Iterable<E> skipWhile(bool test(E value)) {
return SkipWhileIterable<E>(this, test);
}
@@ -527,6 +661,15 @@
///
/// Iterates through elements and returns the first to satisfy [test].
///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.firstWhere((element) => element < 5); // 1
+ /// result = numbers.firstWhere((element) => element > 5); // 6
+ /// result =
+ /// numbers.firstWhere((element) => element > 10, orElse: () => -1); // -1
+ /// ```
+ ///
/// If no element satisfies [test], the result of invoking the [orElse]
/// function is returned.
/// If [orElse] is omitted, it defaults to throwing a [StateError].
@@ -547,6 +690,15 @@
/// checks `test(element)` for each,
/// and finally returns that last one that matched.
///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// var result = numbers.lastWhere((element) => element < 5); // 3
+ /// result = numbers.lastWhere((element) => element > 5); // 7
+ /// result = numbers.lastWhere((element) => element > 10,
+ /// orElse: () => -1); // -1
+ /// ```
+ ///
/// If no element satisfies [test], the result of invoking the [orElse]
/// function is returned.
/// If [orElse] is omitted, it defaults to throwing a [StateError].
@@ -571,6 +723,22 @@
/// If more than one matching element is found, throws [StateError].
/// If no matching element is found, returns the result of [orElse].
/// If [orElse] is omitted, it defaults to throwing a [StateError].
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[2, 2, 10];
+ /// var result = numbers.singleWhere((element) => element > 5); // 10
+ /// ```
+ /// When no matching element is found, the result of calling [orElse] is
+ /// returned instead.
+ /// ```dart continued
+ /// result = numbers.singleWhere((element) => element == 1,
+ /// orElse: () => -1); // -1
+ /// ```
+ /// There must not be more than one matching element.
+ /// ```dart continued
+ /// result = numbers.singleWhere((element) => element == 2); // Throws Error.
+ /// ```
E singleWhere(bool test(E element), {E orElse()?}) {
late E result;
bool foundMatching = false;
@@ -597,6 +765,12 @@
/// May iterate through the elements in iteration order, ignoring the
/// first [index] elements and then returning the next.
/// Some iterables may have a more efficient way to find the element.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 5, 6, 7];
+ /// final elementAt = numbers.elementAt(4); // 6
+ /// ```
E elementAt(int index) {
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;