Lesson 18 of 20

Iterators

Iterators

Iterators are Rust's primary tool for processing sequences of values. They are lazy — they produce values on demand.

The Iterator Trait

trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    // ... many provided methods
}

Creating Iterators

let v = vec![1, 2, 3];
v.iter()       // borrows — yields &T
v.iter_mut()   // mutable borrow — yields &mut T
v.into_iter()  // consumes — yields T
(1..=5)        // range — yields integers

Adapter Methods (lazy)

iter.map(|x| x * 2)           // transform each element
iter.filter(|x| x % 2 == 0)   // keep elements matching predicate
iter.enumerate()               // (index, value) pairs
iter.zip(other)                // pair elements from two iterators
iter.flat_map(|x| some_iter)   // map then flatten
iter.take(n)                   // first n elements
iter.skip(n)                   // skip first n elements
iter.chain(other)              // concatenate two iterators
iter.scan(init, f)             // running state

Consumer Methods (eager)

iter.collect::<Vec<_>>()       // collect into a collection
iter.sum::<i32>()              // sum all elements
iter.count()                   // count elements
iter.max()                     // maximum Option<T>
iter.min()                     // minimum Option<T>
iter.any(|x| x > 0)           // true if any matches
iter.all(|x| x > 0)           // true if all match
iter.find(|x| x > 0)          // first matching element
iter.fold(init, |acc, x| ...) // reduce with accumulator

scan() vs fold()

Both carry state through an iteration, but they serve different purposes:

fold() consumes the entire iterator and returns a single final value:

let total = vec![1, 2, 3].iter().fold(0, |acc, &x| acc + x);
// total = 6

scan() is like fold() but it is lazy and yields each intermediate state, producing a new iterator:

let running: Vec<i32> = vec![1, 2, 3].iter()
    .scan(0, |acc, &x| { *acc += x; Some(*acc) })
    .collect();
// running = [1, 3, 6]

Key differences:

  • fold() returns one value. scan() returns an iterator of intermediate values.
  • fold() is eager (consumes the iterator). scan() is lazy (produces an adapter).
  • scan() can stop early by returning None.

Your Task

  1. sum_of_squares(n: u32) -> u32 — sum of squares from 1 to n.
  2. filter_evens(v: &[i32]) -> Vec<i32> — keep only even numbers.
  3. running_sum(v: &[i32]) -> Vec<i32> — running cumulative sum (use scan()).
  4. flat_zip(a: &[i32], b: &[i32]) -> Vec<i32> — interleave two slices: [a0,b0,a1,b1,...].
  5. product_with_fold(v: &[i32]) -> i32 — compute the product of all elements using fold().
  6. running_max(v: &[i32]) -> Vec<i32> — running maximum using scan(): for each position, the max of all elements up to and including that position.
Rust (Miri) loading...
Loading...
Click "Run" to execute your code.