In Dart, an Iterable is an abstract class that represents a collection of elements that can be iterated over. The most common types of iterables are List, Set, and Map. Understanding iterables is crucial for working with collections in Dart, as they provide a standard way to access and manipulate sequences of elements.

Key Concepts

  1. Iterable Interface: The Iterable class is the base class for all iterable collections. It defines a standard way to access elements sequentially.
  2. Iterator: An Iterator is an object that enables traversal through the elements of an iterable.
  3. Common Methods: Methods like forEach, map, where, reduce, and fold are commonly used to manipulate iterables.

Iterable Interface

The Iterable class provides a way to create custom iterable collections. Here is a simple example of how to implement a custom iterable:

class MyIterable extends Iterable<int> {
  final List<int> _data;

  MyIterable(this._data);

  @override
  Iterator<int> get iterator => _data.iterator;
}

void main() {
  var myIterable = MyIterable([1, 2, 3, 4, 5]);
  for (var value in myIterable) {
    print(value);
  }
}

Explanation

  • MyIterable Class: This class extends Iterable<int> and takes a list of integers as input.
  • iterator Getter: The iterator getter returns an iterator for the underlying list _data.
  • main Function: The main function creates an instance of MyIterable and iterates over its elements using a for-in loop.

Iterator

An Iterator is used to traverse through the elements of an iterable. It has two main methods:

  • moveNext(): Moves to the next element and returns true if there is a next element.
  • current: Returns the current element.

Here is an example of using an iterator directly:

void main() {
  var numbers = [1, 2, 3, 4, 5];
  var iterator = numbers.iterator;

  while (iterator.moveNext()) {
    print(iterator.current);
  }
}

Explanation

  • numbers List: A list of integers.
  • iterator: An iterator for the numbers list.
  • while Loop: The loop continues as long as moveNext() returns true, printing each element.

Common Methods

forEach

The forEach method applies a function to each element of the iterable.

void main() {
  var numbers = [1, 2, 3, 4, 5];
  numbers.forEach((number) {
    print(number);
  });
}

map

The map method transforms each element of the iterable using a provided function.

void main() {
  var numbers = [1, 2, 3, 4, 5];
  var squares = numbers.map((number) => number * number);
  print(squares.toList());
}

where

The where method filters elements based on a condition.

void main() {
  var numbers = [1, 2, 3, 4, 5];
  var evenNumbers = numbers.where((number) => number.isEven);
  print(evenNumbers.toList());
}

reduce

The reduce method combines all elements into a single value using a provided function.

void main() {
  var numbers = [1, 2, 3, 4, 5];
  var sum = numbers.reduce((a, b) => a + b);
  print(sum);
}

fold

The fold method is similar to reduce but allows you to specify an initial value.

void main() {
  var numbers = [1, 2, 3, 4, 5];
  var sum = numbers.fold(0, (a, b) => a + b);
  print(sum);
}

Practical Exercises

Exercise 1: Custom Iterable

Create a custom iterable that generates the first n Fibonacci numbers.

class FibonacciIterable extends Iterable<int> {
  final int count;

  FibonacciIterable(this.count);

  @override
  Iterator<int> get iterator => FibonacciIterator(count);
}

class FibonacciIterator extends Iterator<int> {
  final int count;
  int _current = 0;
  int _next = 1;
  int _index = 0;

  FibonacciIterator(this.count);

  @override
  bool moveNext() {
    if (_index >= count) return false;
    int temp = _current;
    _current = _next;
    _next = temp + _next;
    _index++;
    return true;
  }

  @override
  int get current => _current;
}

void main() {
  var fibonacci = FibonacciIterable(10);
  for (var value in fibonacci) {
    print(value);
  }
}

Solution Explanation

  • FibonacciIterable Class: Extends Iterable<int> and takes the number of Fibonacci numbers to generate.
  • FibonacciIterator Class: Implements the Iterator<int> interface to generate Fibonacci numbers.
  • moveNext Method: Updates the current and next Fibonacci numbers.
  • main Function: Creates an instance of FibonacciIterable and prints the first 10 Fibonacci numbers.

Summary

In this section, we covered the concept of iterables in Dart, including the Iterable interface, Iterator, and common methods like forEach, map, where, reduce, and fold. We also implemented a custom iterable and iterator to generate Fibonacci numbers. Understanding iterables is essential for working with collections in Dart, and mastering these concepts will help you manipulate and traverse data more effectively.

Next, we will delve into Object-Oriented Programming in Dart, starting with classes and objects.

© Copyright 2024. All rights reserved