last modified April 4, 2025
In Dart, Iterable is a fundamental interface for representing collections of elements that can be accessed sequentially. It provides powerful methods for processing and transforming collections.
Iterable is lazy by default, meaning operations are only computed when needed. Many Dart collections like List and Set implement the Iterable interface.
The most common Iterable operations include mapping, filtering, and reducing. These form the basis of collection processing in Dart.
void main() {
var numbers = [1, 2, 3, 4, 5];
// Mapping
var squares = numbers.map((n) => n * n);
print('Squares: $squares');
// Filtering
var evens = numbers.where((n) => n % 2 == 0);
print('Evens: $evens');
// Reducing
var sum = numbers.reduce((a, b) => a + b);
print('Sum: $sum');
}
This example shows three fundamental operations. map transforms each element, where filters elements, and reduce combines elements into a single value.
$ dart main.dart Squares: (1, 4, 9, 16, 25) Evens: (2, 4) Sum: 15
Iterable methods can be chained to create complex processing pipelines. Each operation returns a new Iterable.
void main() {
var words = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
var result = words
.where((word) => word.length > 4)
.map((word) => word.toUpperCase())
.take(3);
print(result);
}
We filter words longer than 4 characters, convert them to uppercase, and take the first 3 results. The operations execute lazily when the result is used.
$ dart main.dart (BANANA, CHERRY, ELDERBERRY)
You can create custom Iterables by implementing the Iterable interface or using sync* generator functions.
Iterable<int> countDown(int from) sync* {
for (int i = from; i >= 0; i--) {
yield i;
}
}
void main() {
var numbers = countDown(5);
print(numbers);
print(numbers.toList());
}
The sync* function creates a lazy Iterable that generates values on demand. The yield keyword provides each value in the sequence.
$ dart main.dart (5, 4, 3, 2, 1, 0) [5, 4, 3, 2, 1, 0]
Iterable provides many advanced methods like expand, fold, and any for complex collection processing.
void main() {
var matrix = [
[1, 2],
[3, 4],
[5, 6]
];
// Flatten matrix
var flattened = matrix.expand((row) => row);
print('Flattened: $flattened');
// Check condition
var hasNegative = flattened.any((n) => n < 0);
print('Has negative: $hasNegative');
// Fold (like reduce but with initial value)
var product = flattened.fold(1, (p, n) => p * n);
print('Product: $product');
}
expand flattens nested collections, any checks if any element matches a condition, and fold is a more flexible version of reduce with an initial value.
$ dart main.dart Flattened: (1, 2, 3, 4, 5, 6) Has negative: false Product: 720
Iterables are lazy by default, meaning operations are only computed when needed. This can improve performance for large collections.
Iterable<int> generateNumbers() sync* {
print('Generator started');
for (int i = 1; i <= 5; i++) {
print('Yielding $i');
yield i;
}
}
void main() {
var numbers = generateNumbers()
.map((n) {
print('Mapping $n');
return n * 2;
})
.take(2);
print('Created pipeline');
print('First: ${numbers.first}');
print('ToList: ${numbers.toList()}');
}
The example demonstrates lazy evaluation. Operations only execute when values are actually needed, as shown by the print statements.
$ dart main.dart Created pipeline Generator started Yielding 1 Mapping 1 First: 2 Yielding 2 Mapping 2 ToList: [2, 4]
This tutorial covered Dart's Iterable interface with practical examples demonstrating its powerful collection processing capabilities.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Dart tutorials.