Iterables and Iteration
In Dart, an Iterable is a collection of elements that can be accessed sequentially. Think of it like a playlist of songs - you can go through each song one by one, but you might not be able to jump directly to song #5 without going through the previous ones first.
What is an Iterable?
An Iterable is an abstract class that represents a collection of objects that can be iterated over. Common examples include:
- Lists
- Sets
- Maps (when iterating over keys, values, or entries)
- Strings (as a sequence of characters)
// Examples of Iterables
List<int> numbers = [1, 2, 3, 4, 5];
Set<String> fruits = {'apple', 'banana', 'orange'};
String message = "Hello";
// All of these are Iterables!
Basic Iteration with for-in Loop
The most common way to iterate through an Iterable is using a for-in loop:
List<String> colors = ['red', 'green', 'blue'];
for (String color in colors) {
print('I like $color');
}
// Output:
// I like red
// I like green
// I like blue
Iterator Pattern
Behind the scenes, Dart uses the Iterator pattern. Every Iterable has an iterator property that returns an Iterator object:
List<int> numbers = [10, 20, 30];
Iterator<int> iterator = numbers.iterator;
while (iterator.moveNext()) {
print(iterator.current);
}
// Output: 10, 20, 30
Useful Iterable Methods
Iterables come with many built-in methods that make working with collections easier:
Transform and Filter
List<int> numbers = [1, 2, 3, 4, 5];
// map() - transform each element
Iterable<int> doubled = numbers.map((n) => n * 2);
print(doubled.toList()); // [2, 4, 6, 8, 10]
// where() - filter elements
Iterable<int> evenNumbers = numbers.where((n) => n % 2 == 0);
print(evenNumbers.toList()); // [2, 4]
Check and Find
List<String> fruits = ['apple', 'banana', 'cherry'];
// Check if any/every element matches a condition
bool hasLongName = fruits.any((fruit) => fruit.length > 6);
print(hasLongName); // false
bool allHaveVowels = fruits.every((fruit) => fruit.contains('a'));
print(allHaveVowels); // false
// Find elements
String? found = fruits.firstWhere((fruit) => fruit.startsWith('b'),
orElse: () => 'not found');
print(found); // banana
Reduce and Fold
List<int> numbers = [1, 2, 3, 4, 5];
// reduce() - combine all elements into a single value
int sum = numbers.reduce((a, b) => a + b);
print(sum); // 15
// fold() - like reduce but with an initial value
int product = numbers.fold(1, (prev, element) => prev * element);
print(product); // 120
Lazy Evaluation
One cool thing about Iterables is that many operations are lazy - they don't do the work until you actually need the results:
List<int> numbers = [1, 2, 3, 4, 5];
// This doesn't actually do any multiplication yet!
Iterable<int> doubled = numbers.map((n) => n * 2);
// The multiplication happens when we iterate
for (int value in doubled) {
print(value); // Now the multiplication happens
}
Converting Between Types
You can easily convert between different collection types:
List<int> list = [1, 2, 3, 2, 1];
Set<int> uniqueSet = list.toSet(); // {1, 2, 3}
List<int> backToList = uniqueSet.toList(); // [1, 2, 3]
// Convert to other iterables
Iterable<String> strings = list.map((n) => n.toString());
Common Iterable Properties
| Property | Description | Example |
|---|---|---|
length | Number of elements | [1,2,3].length → 3 |
isEmpty | True if no elements | [].isEmpty → true |
isNotEmpty | True if has elements | [1].isNotEmpty → true |
first | First element | [1,2,3].first → 1 |
last | Last element | [1,2,3].last → 3 |
Remember: Iterables are the foundation of working with collections in Dart. They provide a consistent way to work with different types of data collections, making your code more flexible and reusable!