The Iterable interface can be defined as the common behavior of all classes in the collection framework that supports a mechanism to iterate through all the elements of a collection. It is an object that uses an Iterator interface to iterate over all the elements in a collection. There are two abstract classes, IterableBase
and IterableMixin
, that implement the Iterator interface. The IterableMixin
class is perfectly suited to be extended in the mixin solutions. If you plan to create your own implementation of the Iterable interface, you need to extend one of them. There are many different methods in the Iterable interface to help you manipulate the elements in a collection.
Here is a list of the read-only properties that are common for all collections:
length
: This property returns the number of elements in a collectionisEmpty
: This property returns true
if there are no elements in a collectionisNotEmpty
: This property returns true
if there is at least one element in a collectionfirst
: This property returns the first element of a collection or throws StateError
if the collection is emptylast
: This property returns the last element of a collection or throws StateError
if the collection is emptysingle
: This property returns a single element in a collection. It throws StateError
if the collection is empty or has more than one elementiterator
: This property returns a reference on instance of the Iterator class that iterates over the elements of the collectionSometimes, you want to know if all or any of the objects in a collection comply with a specific condition. The following methods check whether the collection conforms to specific conditions:
every
: This method returns true
if every element in the collection satisfies the specified condition. This can be seen in the following code:List colors = ['red', 'green', 'blue']; print(colors.every((color) => color != null || color != '')); // => true
any
: This method returns true
if one element in the collection satisfies the specified condition. This is illustrated in the following code:List colors = ['red', 'green', 'blue']; print(colors.any((color) => color == 'red')); // => true
The search over collection list includes the following methods that are used to search for an element in a collection:
contains
: This method returns true
if the collection contains an element that is equal to the requested one. This is shown in the following code:List colors = ['red', 'green', 'blue']; print(colors.contains('red')); // => true
elementAt
: This method returns the indexth
element. Exactly which object is returned depends on the sorting algorithm implemented by the specific collection class that you're using, as shown in the following code:List colors = ['red', 'green', 'blue']; print(colors.elementAt(0)); // => red
firstWhere
: This method returns the first element in the collection that satisfies the given predicate test or the result of the orElse
function. It throws StateError
if orElse
was not specified, as illustrated in the following code:List colors = ['red', 'green', 'blue']; print(colors.firstWhere((color) => color == 'orange', orElse:() => 'orange')); // => orange
lastWhere
: This method returns the last element in the collection that satisfies the given predicate test or the result of the orElse
function. It throws StateError
if orElse
was not specified, as shown in the following code:List colors = ['red', 'green', 'blue']; print(colors.lastWhere((color) => color != 'orange', orElse:() => '')); // => blue
singleWhere
: This method returns a single element of the collection that satisfies the test. If the collection is empty or more than one element matches, then it throws StateError
. The code is as follows:List colors = ['red', 'green', 'blue']; print(colors.singleWhere((color) => color == 'red')); // => red
The following list includes methods to create a new collection from the original one; all of them return Lazy Iterable results:
expand
: This method returns new collections by expanding each element of the original one to zero or more elements. This can be seen in the following code:List colors = ['red', 'green', 'blue']; print(colors.expand((color) { return color == 'red' ? ['orange', 'red', 'yellow'] : [color]; })); // => [orange, red, yellow, green, blue]
map
: This method creates a new collection of elements based on the elements from the original collection that are transformed with specified function. The code is as follows:List colors = ['red', 'green', 'blue']; print(colors.map((color) { if (color == 'green') return 'orange'; if (color == 'blue') return 'yellow'; return color; })); // => ['red', 'orange', 'yellow']
take
: This method returns an Iterable collection with a specified number of elements from the original collection. The value of these elements must not be negative. If the number of requested elements is more than the actual number of elements, then it returns all the elements from the collection:List nums = [1, 2, 3, 4, 5, 6]; print(nums.take(7)); // => [1, 2, 3, 4, 5, 6]
takeWhile
: This method returns an Iterable collection that stops once the test is not satisfied anymore. This is illustrated in the following code:List nums = [1, 2, 3, 4, 5, 6]; print(nums.takeWhile((element) => element < 5)); // => [1, 2, 3, 4]
skip
: This method returns an Iterable collection that skips the specified number of initial elements. If it has fewer elements than the specified number, then the resulting Iterable collection is empty. Also, the specified number must not be negative. The code is as follows:List nums = [1, 2, 3, 4, 5, 6]; print(nums.skip(4)); // => [5, 6]
skipWhile
: This method returns an Iterable collection that skips the elements while the test is satisfied. This is shown in the following code:List nums = [1, 2, 3, 4, 5, 6]; print(nums.skipWhile((element) => element <= 4)); // => [5, 6]
where
: This method returns a Lazy Iterable collection with all the elements that satisfy the predicate test. This is illustrated in the following code:List nums = [1, 2, 3, 4, 5, 6]; print(nums.where((element) => element > 1 && element < 5)); // => [2, 3, 4]
toList
: This method creates a list that contains the elements of the original collection. It creates a fixed length List
if the growable
attribute is false
:List nums = [1, 2, 3]; print(nums.toList(growable:false)); // => [1, 2, 3]
toSet
: This method creates a set that contains the elements of the original collection. It ignores the duplicate elements. The code is as follows:List nums = [1, 2, 1]; print(nums.toSet()); // => {1, 2}
The following list includes methods to reduce the number of elements in a collection:
reduce
: This method reduces the collection to a single value by iteratively combining the elements of the collection using the provided function. If the collection is empty, this results in StateError
. In the following example, we will calculate the sum of all elements in the collection:List nums = [1, 2, 3]; print(nums.reduce((sum, element) => sum + element)); // => 6
fold
: This method reduces the collection to a single value by iteratively combining each element of the collection with an existing value using the specified function. Here, we have to specify the initial value and aggregation function:List nums = [1, 2, 3]; print(nums.fold(0, (acc, element) => acc + element)); // => 6
The following method is used to convert all the elements of a collection:
join
: This method converts each element of the collection into a string and returns the concatenated result separated with an optional separator. If the collection is empty, it doesn't actually modify the type of the elements in the collection, but just returns an empty string:List nums = [1, 2, 3]; print(nums.join(' - ')); // => 1 - 2 - 3
The Iterable interface has a factory method that helps to create a new Iterable interface and is filled with a specified number of values generated by a generator function, as shown in the following code:
Iterable generated = new Iterable.generate(4, (count) => "Is $count"); print(generated); // => [Is 0, Is 1, Is 2, Is 3]
If the generator function is absent, this method generates a collection with only the integer values:
Iterable generated = new Iterable.generate(4); print(generated); // => [0, 1, 2, 3]
The Lazy Iterable term is used plenty of times in Iterable interfaces. It is an iteration strategy that delays the iteration of a collection until its value is needed and avoids repeated iterations. In the following example, our code iterates over the list of numbers.
The where
method prints the information about the current fetched element. This function calls the object only when we actually fetch the element in the forEach
method of the Iterable interface, as shown in the following code:
lazyIterable() { List nums = [1, 2, 3]; print('Get Iterable for $nums'), Iterable iterable = nums.where((int i) { print('Fetched $i'), return i.isOdd; }); print('Start fetching'), iterable.forEach((int i) { print("Received $i"); }); }
Here is the output of the preceding function:
Get Iterable for [1, 2, 3] Start fetching Fetched 1 Received 1 Fetched 2 Fetched 3 Received 3
The following are the benefits of the Lazy Iterable:
Bear in mind that iteration over the Lazy Iterable could be much slower than a normal iteration because the code incurs the cost of an invocation to fetch the next item from the Iterable source.
3.143.5.201