13.2 Common Iterator Methods

This section introduces widely used iterator methods. We categorize them into adapters (lazy) and consumers (eager).

13.2.1 Iterator Adapters (Lazy)

map()

Applies a closure or function to each element, returning a new iterator of transformed items:

fn main() {
    let numbers = vec![1, 2, 3, 4];
    let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
    println!("{:?}", doubled); // [2, 4, 6, 8]
}

You can pass a named function if it matches the required signature:

fn double(i: &i32) -> i32 {
    i * 2
}

fn main() {
    let numbers = vec![1, 2, 3, 4];
    let doubled: Vec<i32> = numbers.iter().map(double).collect();
    println!("{:?}", doubled); // [2, 4, 6, 8]
}

filter()

Retains only elements that satisfy a given predicate:

fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6];
    let even: Vec<i32> = numbers.iter().filter(|&&x| x % 2 == 0).cloned().collect();
    println!("{:?}", even); // [2, 4, 6]
}

take()

Yields the first n elements:

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let first_three: Vec<i32> = numbers.iter().take(3).cloned().collect();
    println!("{:?}", first_three); // [1, 2, 3]
}

skip()

Skips the first n elements, yielding the remainder:

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let skipped: Vec<i32> = numbers.iter().skip(2).cloned().collect();
    println!("{:?}", skipped); // [3, 4, 5]
}

take_while() and skip_while()

  • take_while() yields items until the predicate becomes false.
  • skip_while() skips items while the predicate is true, yielding the rest once the predicate is false.
fn main() {
    let numbers = vec![1, 2, 3, 1, 2];
    let initial_run: Vec<i32> = numbers
        .iter()
        .cloned()
        .take_while(|&x| x < 3)
        .collect();
    println!("{:?}", initial_run); // [1, 2]

    let after_first_three: Vec<i32> = numbers
        .iter()
        .cloned()
        .skip_while(|&x| x < 3)
        .collect();
    println!("{:?}", after_first_three); // [3, 1, 2]
}

enumerate()

Yields an (index, element) pair:

fn main() {
    let names = vec!["Alice", "Bob", "Charlie"];
    for (index, name) in names.iter().enumerate() {
        print!("{}: {}; ", index, name);
    }
    // 0: Alice; 1: Bob; 2: Charlie;
}

13.2.2 Consuming Iterator Methods (Eager)

collect()

Consumes the iterator, gathering all elements into a collection (e.g., Vec<T>, String, etc.):

fn main() {
    let numbers = vec![1, 2, 3];
    let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
    println!("{:?}", doubled); // [2, 4, 6]
}

sum()

Computes the sum of the elements:

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let total: i32 = numbers.iter().sum();
    println!("Total: {}", total); // Total: 15
}

fold()

Combines elements into a single value using a custom operation:

fn main() {
    let numbers = vec![1, 2, 3, 4];
    let product = numbers.iter().fold(1, |acc, &x| acc * x);
    println!("{}", product); // 24
}

for_each()

Applies a closure to each item:

fn main() {
    let numbers = vec![1, 2, 3];
    numbers.iter().for_each(|x| print!("{}, ", x));
    // 1, 2, 3,
}

any() and all()

  • any(): Returns true if at least one element satisfies the predicate.
  • all(): Returns true if every element satisfies the predicate.
fn main() {
    let numbers = vec![2, 4, 6, 7];
    let has_odd = numbers.iter().any(|&x| x % 2 != 0);
    let all_even = numbers.iter().all(|&x| x % 2 == 0);

    println!("Has odd? {}", has_odd);       // true
    println!("All even? {}", all_even);    // false
}

These methods short-circuit as soon as the outcome is known.