๐Ÿฆ€ Functional Rust
๐ŸŽฌ How Rust Iterators Work Lazy evaluation, chaining, collect(), and zero-cost abstractions.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Iterators are lazy โ€” .map(), .filter(), .take() build a chain but do no work until consumed

โ€ข .collect() triggers evaluation, transforming the chain into a Vec, HashMap, or other collection

โ€ข Zero-cost abstraction: iterator chains compile to the same machine code as hand-written loops

โ€ข .iter() borrows, .into_iter() consumes, .iter_mut() borrows mutably

โ€ข Chaining replaces nested loops with a readable, composable pipeline

279: Iterator nth()

Difficulty: 1 Level: Beginner Skip to the n-th element of an iterator (0-indexed), consuming all elements before it in the process.

The Problem This Solves

You need the third item in a CSV after skipping the header, or the fifth element of a filtered stream, or you want to advance a stateful iterator past the first few items. Without `nth`, you'd call `skip(n).next()` โ€” which works but requires knowing the relationship between `skip` and `next`. Or you'd collect everything into a Vec and index it โ€” wasteful if you only need one element. `nth(n)` is the direct expression of "give me element at position n." It's 0-indexed (nth(0) is the first element, like array indexing). It's O(n) for most iterators โ€” it has to skip through n elements. For random access on known collections, direct indexing `v[n]` is O(1); use `nth` when you're working with a pipeline. Critical behavior: `nth` consumes the iterator up to and including index n. After calling `iter.nth(2)`, the iterator is positioned at index 3. Calling `iter.nth(0)` afterward returns the element at the original index 3.

The Intuition

Advance the iterator n positions, discard everything before position n, and return the element at position n as `Option<T>`.

How It Works in Rust

let nums = [10i32, 20, 30, 40, 50];

nums.iter().nth(0);   // Some(&10) โ€” first element
nums.iter().nth(2);   // Some(&30) โ€” third element (0-indexed)
nums.iter().nth(10);  // None โ€” out of bounds

// nth advances the iterator โ€” subsequent calls see the rest
let mut iter = nums.iter();
iter.nth(1);  // Some(&20)  โ€” skips index 0, returns index 1
iter.nth(0);  // Some(&30)  โ€” iterator is now at index 2; returns index 2

// Skip CSV header, get the second data row
let csv = "name,age\nAlice,30\nBob,25\nCarol,35";
csv.lines().nth(2);  // Some("Bob,25") โ€” skip header + Alice

// nth on a filtered iterator
let fourth_even = (0i32..20).filter(|x| x % 2 == 0).nth(3);
// โ†’ Some(6) โ€” the evens are [0,2,4,6,...]; index 3 is 6

What This Unlocks

Key Differences

ConceptOCamlRust
Get by index`List.nth lst n``iter.nth(n)`
Out of bounds`Failure` exceptionReturns `None`
Indexing base0-based0-based
Consumes itemsNo (list persists)Yes โ€” advances iterator state
After callList unchangedIterator is past index n
//! 279. Random access with nth()
//!
//! `nth(n)` returns `Option<T>` at index n, consuming elements 0..n in the process.

fn main() {
    let nums = [10i32, 20, 30, 40, 50];

    // nth on a slice iterator
    println!("0th: {:?}", nums.iter().nth(0));
    println!("2nd: {:?}", nums.iter().nth(2));
    println!("Out of bounds: {:?}", nums.iter().nth(10));

    // nth consumes elements โ€” re-use iterator
    let mut iter = nums.iter();
    println!("iter.nth(1) = {:?}", iter.nth(1)); // 20
    println!("iter.nth(0) = {:?}", iter.nth(0)); // 30 (iterator advanced)

    // nth on a filtered iterator (O(n))
    let second_even = (0i32..20).filter(|x| x % 2 == 0).nth(3);
    println!("4th even in 0..20: {:?}", second_even);

    // Practical: skip header, get second data line
    let csv = "name,age
Alice,30
Bob,25
Carol,35";
    let second_row = csv.lines().nth(2);
    println!("Third line of CSV: {:?}", second_row);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_nth_basic() {
        let v = [10i32, 20, 30, 40];
        assert_eq!(v.iter().nth(2), Some(&30));
    }

    #[test]
    fn test_nth_out_of_bounds() {
        let v = [1i32, 2];
        assert_eq!(v.iter().nth(5), None);
    }

    #[test]
    fn test_nth_advances_iterator() {
        let mut it = [1i32, 2, 3, 4, 5].iter();
        assert_eq!(it.nth(1), Some(&2)); // consumes 1,2
        assert_eq!(it.nth(0), Some(&3)); // now at 3
    }

    #[test]
    fn test_nth_zero() {
        let v = [99i32];
        assert_eq!(v.iter().nth(0), Some(&99));
    }
}
(* 279. Random access with nth() - OCaml *)

let safe_nth lst n =
  if n < 0 || n >= List.length lst then None
  else Some (List.nth lst n)

let () =
  let nums = [10; 20; 30; 40; 50] in
  Printf.printf "0th: %s\n" (match safe_nth nums 0 with Some n -> string_of_int n | None -> "None");
  Printf.printf "2nd: %s\n" (match safe_nth nums 2 with Some n -> string_of_int n | None -> "None");
  Printf.printf "10th: %s\n" (match safe_nth nums 10 with Some n -> string_of_int n | None -> "None");

  (* Nth after filtering *)
  let evens = List.filter (fun x -> x mod 2 = 0) nums in
  Printf.printf "2nd even: %s\n"
    (match safe_nth evens 1 with Some n -> string_of_int n | None -> "None")