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

091: Zip Unzip

Difficulty: Intermediate Category: Iterators Concept: Zip two iterators and unzip pairs Key Insight: Zip interleaves two iterators element-wise; unzip is the inverse โ€” separates pairs into two collections
// 091: Zip and Unzip

fn main() {
    // zip
    let a = vec![1, 2, 3];
    let b = vec!["a", "b", "c"];
    let zipped: Vec<_> = a.iter().zip(b.iter()).collect();
    println!("zip: {:?}", zipped);

    // unzip
    let pairs = vec![(1, "a"), (2, "b"), (3, "c")];
    let (nums, strs): (Vec<i32>, Vec<&str>) = pairs.into_iter().unzip();
    println!("unzip: {:?} {:?}", nums, strs);

    // zip_with
    let sums: Vec<i32> = [1, 2, 3].iter().zip([10, 20, 30].iter()).map(|(a, b)| a + b).collect();
    println!("zip_with +: {:?}", sums);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_zip() {
        let v: Vec<_> = [1, 2, 3].iter().zip(["a", "b", "c"].iter()).collect();
        assert_eq!(v, vec![(&1, &"a"), (&2, &"b"), (&3, &"c")]);
    }

    #[test]
    fn test_zip_unequal() {
        let v: Vec<_> = [1, 2].iter().zip([10, 20, 30].iter()).collect();
        assert_eq!(v.len(), 2);
    }

    #[test]
    fn test_unzip() {
        let (a, b): (Vec<i32>, Vec<&str>) = vec![(1, "a"), (2, "b")].into_iter().unzip();
        assert_eq!(a, vec![1, 2]);
        assert_eq!(b, vec!["a", "b"]);
    }

    #[test]
    fn test_zip_with() {
        let v: Vec<i32> = [1, 2, 3].iter().zip([10, 20, 30].iter()).map(|(a, b)| a + b).collect();
        assert_eq!(v, vec![11, 22, 33]);
    }
}
(* 091: Zip and Unzip *)

(* Approach 1: Zip two lists *)
let rec zip l1 l2 =
  match l1, l2 with
  | [], _ | _, [] -> []
  | x :: xs, y :: ys -> (x, y) :: zip xs ys

(* Approach 2: Unzip pairs *)
let unzip pairs =
  List.fold_right (fun (a, b) (la, lb) -> (a :: la, b :: lb)) pairs ([], [])

(* Approach 3: Zip with function *)
let rec zip_with f l1 l2 =
  match l1, l2 with
  | [], _ | _, [] -> []
  | x :: xs, y :: ys -> f x y :: zip_with f xs ys

(* Tests *)
let () =
  assert (zip [1; 2; 3] ["a"; "b"; "c"] = [(1, "a"); (2, "b"); (3, "c")]);
  assert (zip [1; 2] [10; 20; 30] = [(1, 10); (2, 20)]);
  assert (unzip [(1, "a"); (2, "b")] = ([1; 2], ["a"; "b"]));
  assert (zip_with ( + ) [1; 2; 3] [10; 20; 30] = [11; 22; 33]);
  Printf.printf "โœ“ All tests passed\n"

๐Ÿ“Š Detailed Comparison

Core Insight

Zip interleaves two iterators element-wise; unzip is the inverse โ€” separates pairs into two collections

OCaml Approach

  • See example.ml for implementation

Rust Approach

  • See example.rs for implementation

Comparison Table

FeatureOCamlRust
Seeexample.mlexample.rs