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

275: Iterator min() and max()

Difficulty: 1 Level: Beginner Consume an iterator to find its minimum or maximum element, returning `Option<T>` to handle the empty case.

The Problem This Solves

You want the smallest or largest value in a collection. Without `min()` and `max()`, you'd write a fold with a running minimum, initialize it to `i32::MAX`, and hope you remembered to handle the empty case. Or you'd sort and take the first element โ€” O(n log n) when O(n) is all you need. The more interesting problem is finding the element with the minimum of a derived property โ€” the shortest string, the student with the highest score, the point closest to the origin. `.min_by_key(|x| x.score)` handles this without implementing `Ord` on your struct or creating intermediate (value, key) tuples. One important constraint: `min()` and `max()` require `Ord`. That means `f64` doesn't work directly โ€” floats don't have a total ordering because of `NaN`. The example shows the `reduce(f64::min)` workaround for floats.

The Intuition

Walk the entire iterator, keep track of the extreme value seen so far, return it wrapped in `Some` โ€” or `None` if the iterator was empty.

How It Works in Rust

let nums = [3i32, 1, 4, 1, 5, 9, 2, 6];
println!("{:?}", nums.iter().min());  // Some(1)
println!("{:?}", nums.iter().max());  // Some(9)

// Empty iterator โ†’ None (not a crash, not a sentinel value)
let empty: Vec<i32> = vec![];
println!("{:?}", empty.iter().min());  // None

// min/max by a derived key โ€” no need to implement Ord
let words = ["banana", "apple", "fig", "cherry"];
words.iter().min_by_key(|w| w.len());  // Some("fig")
words.iter().max_by_key(|w| w.len());  // Some("banana")

// Works on any type with a comparable field
struct Student { name: &'static str, score: u32 }
let students = [/* ... */];
students.iter().max_by_key(|s| s.score);  // top scorer

// f64 doesn't implement Ord โ€” use reduce instead
let floats = [3.14f64, 1.41, 2.71];
let min_f = floats.iter().cloned().reduce(f64::min);  // Some(1.41)

What This Unlocks

Key Differences

ConceptOCamlRust
Min of list`List.fold_left min max_int lst``iter.min()`
Empty listManual guard or exceptionReturns `None` automatically
Float minWorks (but NaN is UB)Must use `reduce(f64::min)` or `min_by`
By keyManual: `List.sort` + `List.hd``.min_by_key(f)` / `.max_by_key(f)`
Return type`'a` (unwrapped)`Option<T>`
//! 275. Finding extremes: min() and max()
//!
//! `min()` and `max()` return `Option<T>` โ€” None for empty, requires `Ord`.


#[cfg(test)]
mod tests {
    #[test]
    fn test_min_max() {
        let v = [5i32, 3, 8, 1, 9, 2];
        assert_eq!(v.iter().min(), Some(&1));
        assert_eq!(v.iter().max(), Some(&9));
    }

    #[test]
    fn test_min_max_empty() {
        let empty: Vec<i32> = vec![];
        assert_eq!(empty.iter().min(), None);
        assert_eq!(empty.iter().max(), None);
    }

    #[test]
    fn test_min_by_key() {
        let words = ["hello", "hi", "world"];
        assert_eq!(words.iter().min_by_key(|w| w.len()), Some(&"hi"));
    }

    #[test]
    fn test_max_by_key() {
        let words = ["hello", "hi", "world"];
        assert_eq!(words.iter().max_by_key(|w| w.len()), Some(&"world"));
    }
}
(* 275. Finding extremes: min() and max() - OCaml *)

let list_min = function [] -> None | lst -> Some (List.fold_left min max_int lst)
let list_max = function [] -> None | lst -> Some (List.fold_left max min_int lst)

let () =
  let nums = [3; 1; 4; 1; 5; 9; 2; 6; 5; 3; 5] in
  Printf.printf "Min: %s\n" (match list_min nums with Some n -> string_of_int n | None -> "None");
  Printf.printf "Max: %s\n" (match list_max nums with Some n -> string_of_int n | None -> "None");
  Printf.printf "Min of []: %s\n" (match list_min [] with None -> "None" | Some n -> string_of_int n);

  let words = ["banana"; "apple"; "fig"; "kiwi"; "cherry"] in
  let shortest = List.fold_left (fun acc w ->
    if String.length w < String.length acc then w else acc
  ) (List.hd words) (List.tl words) in
  Printf.printf "Shortest: %s\n" shortest;

  let longest = List.fold_left (fun acc w ->
    if String.length w > String.length acc then w else acc
  ) (List.hd words) (List.tl words) in
  Printf.printf "Longest: %s\n" longest