๐Ÿฆ€ 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

257: Pairing Elements with zip()

Difficulty: 1 Level: Beginner Combine two iterators element-by-element into pairs โ€” stops at the shorter one, never panics on length mismatch.

The Problem This Solves

You have two parallel sequences and you need to process them together: names and scores, keys and values, timestamps and readings. The naive approach is an index loop: `for i in 0..n { process(a[i], b[i]); }` โ€” but you need to know `n`, you need bounds checking, and the intent ("process in parallel") is buried in the mechanics. `zip()` expresses this directly: "pair up these two sequences, one element at a time." No indices, no bounds, no off-by-one. The result is an iterator of tuples `(a_item, b_item)` that you can pass to any iterator adapter โ€” `map`, `filter`, `collect`, `for_each`. The length handling is important: `zip()` stops at the shorter iterator. This is the safe choice โ€” you never get an out-of-bounds access or a panic. OCaml's `List.combine` raises `Invalid_argument` on length mismatch. Know which behaviour you need; in most cases, silent truncation is correct.

The Intuition

Zip is like a zipper: two separate rows of teeth, interlocked one pair at a time. You get as many pairs as the shorter side allows. After that, the zipper stops. Each call to `next()` on the zip iterator calls `next()` on both inner iterators and pairs the results. If either returns `None`, the zip returns `None`. The whole thing is lazy โ€” nothing is computed until you consume the zip. Building a `HashMap` from two parallel slices (one of keys, one of values) is idiomatic: `keys.into_iter().zip(values).collect::<HashMap<_,_>>()`. This is the canonical Rust idiom for constructing a map from two independent lists.

How It Works in Rust

// Iterate two slices in parallel
let names = ["Alice", "Bob", "Carol"];
let scores = [95u32, 87, 92];
for (name, score) in names.iter().zip(scores.iter()) {
 println!("{}: {}", name, score);
}

// Build a HashMap from two iterators โ€” canonical idiom
let keys   = vec!["a", "b", "c"];
let values = vec![1i32, 2, 3];
let map: HashMap<_, _> = keys.into_iter().zip(values).collect();

// zip truncates at the shorter โ€” no panic, no error
let long  = [1i32, 2, 3, 4, 5];
let short = ["x", "y"];
let pairs: Vec<_> = long.iter().zip(short.iter()).collect();
// pairs.len() == 2  (not 5)

// Enumerate is zip with 0..
let items = ["a", "b", "c"];
for (i, item) in items.iter().enumerate() {
 println!("{}: {}", i, item);  // 0:a  1:b  2:c
}
// enumerate() is equivalent to (0..).zip(items.iter())
`zip` is lazy: calling `.zip()` doesn't compute anything. Elements are produced only when consumed by a `for` loop, `.collect()`, or another adapter.

What This Unlocks

Key Differences

ConceptOCamlRust
Syntax`List.combine xs ys``xs.iter().zip(ys.iter())`
Result type`('a * 'b) list` โ€” eager`Zip<IterA, IterB>` โ€” lazy iterator
Length mismatchRaises `Invalid_argument`Silent truncation at shorter
LazinessEager (computes all pairs)Lazy โ€” produces pairs on demand
Index-basedManual `List.nth` or `Array.get``.enumerate()` for `(index, item)`
//! 257. Pairing elements with zip()
//!
//! `zip()` pairs elements from two iterators, stopping at the shorter one.

fn main() {
    let names = ["Alice", "Bob", "Carol"];
    let scores = [95u32, 87, 92];
    for (name, score) in names.iter().zip(scores.iter()) {
        println!("{}: {}", name, score);
    }

    let keys = vec!["a".to_string(), "b".to_string(), "c".to_string()];
    let values = vec![1i32, 2, 3];
    let map: std::collections::HashMap<String, i32> =
        keys.into_iter().zip(values).collect();
    println!("Map: {:?}", map);

    // zip truncates at shorter
    let long  = [1i32, 2, 3, 4, 5];
    let short = ["x", "y"];
    let truncated: Vec<_> = long.iter().zip(short.iter()).collect();
    println!("Truncated zip length: {}", truncated.len());

    let xs = 0i32..4;
    let ys = (0i32..4).map(|y| y * y);
    let coords: Vec<(i32, i32)> = xs.zip(ys).collect();
    println!("Coordinates: {:?}", coords);

    let (left, right): (Vec<i32>, Vec<i32>) = vec![(1,10),(2,20),(3,30)]
        .into_iter().unzip();
    println!("Left: {:?}, Right: {:?}", left, right);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_zip_basic() {
        let a = [1i32, 2, 3];
        let b = ["x", "y", "z"];
        let result: Vec<_> = a.iter().zip(b.iter()).collect();
        assert_eq!(result.len(), 3);
        assert_eq!(result[0], (&1, &"x"));
    }

    #[test]
    fn test_zip_truncates() {
        let a = [1i32, 2, 3, 4, 5];
        let b = [10i32, 20];
        let result: Vec<_> = a.iter().zip(b.iter()).collect();
        assert_eq!(result.len(), 2);
    }

    #[test]
    fn test_zip_into_hashmap() {
        let keys = vec!["a", "b"];
        let vals = vec![1i32, 2];
        let map: std::collections::HashMap<_, _> = keys.into_iter().zip(vals).collect();
        assert_eq!(map["a"], 1);
        assert_eq!(map["b"], 2);
    }
}
(* 257. Pairing elements with zip() - OCaml *)

let () =
  let names = ["Alice"; "Bob"; "Carol"] in
  let scores = [95; 87; 92] in
  let paired = List.combine names scores in
  List.iter (fun (name, score) ->
    Printf.printf "%s: %d\n" name score
  ) paired;

  let (ns, ss) = List.split paired in
  Printf.printf "Names: %s\n" (String.concat ", " ns);
  Printf.printf "Scores: %s\n" (String.concat ", " (List.map string_of_int ss));

  let indexed = List.mapi (fun i x -> (i, x)) ["a"; "b"; "c"] in
  List.iter (fun (i, x) -> Printf.printf "%d: %s\n" i x) indexed