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

271: Transform-and-Find with find_map()

Difficulty: 2 Level: Intermediate Find the first element that both matches and transforms successfully โ€” returns the transformed value, not the original.

The Problem This Solves

You're scanning a list looking for the first element that passes a test and needs to be transformed before you use it. Parse the first valid integer from a list of strings. Find the first filename with a `.rs` extension and return just the stem. Find the first key=value pair in a config file and return the parsed pair. Without `find_map`, you'd write `filter_map(f).next()` โ€” or a manual loop with an `if let Some(x) = transform(element)` that breaks on success. Both work, but `find_map` makes the intent explicit: "find the first element for which this transformation succeeds." The key is that the closure returns `Option<B>` โ€” `None` means "skip this element", `Some(value)` means "found it, return this value." OCaml doesn't have a built-in equivalent; you'd use `List.find_map` (added in OCaml 4.10) or compose `filter_map` with `List.nth`.

The Intuition

`find_map(f)` applies `f` to each element in order. The first time `f` returns `Some(value)`, it stops and returns that `Some(value)`. If `f` returns `None` for every element, the result is `None`.
let strings = ["hello", "42", "world", "17"];
let first_int = strings.iter().find_map(|s| s.parse::<i32>().ok());
// โ†’ Some(42)   stops at "42", never processes "world" or "17"

How It Works in Rust

let strings = ["hello", "42", "world", "17", "foo"];

// Parse: first valid integer
let first_int = strings.iter().find_map(|s| s.parse::<i32>().ok());
// โ†’ Some(42)

// Conditional transform: first word longer than 4 chars, return its length
let first_long_len = strings.iter()
 .find_map(|s| if s.len() > 4 { Some(s.len()) } else { None });
// โ†’ Some(5)  ("hello" has 5 chars)

// Parse key=value pairs โ€” use ? operator inside closure
let env_vars = ["PATH=/usr/bin", "HOME=/root", "BAD", "USER=alice"];
let first_kv = env_vars.iter().find_map(|s| {
 let mut parts = s.splitn(2, '=');
 let key = parts.next()?;   // None if empty
 let val = parts.next()?;   // None if no '='
 Some((key, val))
});
// โ†’ Some(("PATH", "/usr/bin"))

// Strip suffix: first .rs file stem
let files = ["main.txt", "lib.rs", "README.md", "util.rs"];
let first_rs_stem = files.iter().find_map(|f| f.strip_suffix(".rs"));
// โ†’ Some("lib")

// find_map(f) == filter_map(f).next()  โ€” they're equivalent
let equiv = strings.iter().filter_map(|s| s.parse::<i32>().ok()).next();
assert_eq!(first_int, equiv);
The `?` operator inside the closure is idiomatic โ€” it converts `None`/`Err` to `None` and returns early from the closure.

What This Unlocks

Key Differences

ConceptOCamlRust
Find and transform`List.find_map` (4.10+)`iter.find_map(f)`
Stops at first `Some`YesYes โ€” lazy, early exit
Equivalent to`filter_map f lst \> List.hd_opt``.filter_map(f).next()`
Returns`'b option``Option<B>`
Closure return type`'a -> 'b option``FnMut(T) -> Option<B>`
//! 271. Transform-and-find with find_map()
//!
//! `find_map(f)` finds the first `Some(...)` result โ€” single pass, lazy.

fn main() {
    let strings = ["hello", "42", "world", "17", "foo"];

    let first_int = strings.iter().find_map(|s| s.parse::<i32>().ok());
    println!("First int: {:?}", first_int);

    let first_long_len = strings.iter()
        .find_map(|s| if s.len() > 4 { Some(s.len()) } else { None });
    println!("First long word length: {:?}", first_long_len);

    let env_vars = ["PATH=/usr/bin", "HOME=/root", "BAD", "USER=alice"];
    let first_kv = env_vars.iter().find_map(|s| {
        let mut parts = s.splitn(2, '=');
        let key = parts.next()?;
        let val = parts.next()?;
        Some((key, val))
    });
    println!("First key=value: {:?}", first_kv);

    let files = ["main.txt", "lib.rs", "README.md", "util.rs"];
    let first_rs_stem = files.iter().find_map(|f| f.strip_suffix(".rs"));
    println!("First .rs stem: {:?}", first_rs_stem);

    // Equivalence with filter_map + next
    let equiv = strings.iter().filter_map(|s| s.parse::<i32>().ok()).next();
    assert_eq!(first_int, equiv);
    println!("find_map == filter_map+next: true");
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_find_map_parse() {
        let strings = ["foo", "bar", "42", "baz"];
        let result = strings.iter().find_map(|s| s.parse::<i32>().ok());
        assert_eq!(result, Some(42));
    }

    #[test]
    fn test_find_map_none() {
        let strings = ["foo", "bar"];
        let result = strings.iter().find_map(|s| s.parse::<i32>().ok());
        assert_eq!(result, None);
    }

    #[test]
    fn test_find_map_first_match() {
        let nums = [1i32, 2, 3, 4, 5];
        let result = nums.iter().find_map(|&x| if x > 3 { Some(x * 10) } else { None });
        assert_eq!(result, Some(40));
    }
}
(* 271. Transform-and-find with find_map() - OCaml *)

let find_map f lst =
  let rec aux = function
    | [] -> None
    | x :: xs -> (match f x with Some _ as r -> r | None -> aux xs)
  in aux lst

let () =
  let strings = ["hello"; "42"; "world"; "17"; "foo"] in
  let first_int = find_map int_of_string_opt strings in
  Printf.printf "First int: %s\n"
    (match first_int with Some n -> string_of_int n | None -> "None");

  let first_long_len = find_map (fun w ->
    let l = String.length w in if l > 4 then Some l else None
  ) strings in
  Printf.printf "First long word length: %s\n"
    (match first_long_len with Some n -> string_of_int n | None -> "None");

  let env_vars = ["PATH=/usr/bin"; "HOME=/root"; "BAD"; "USER=alice"] in
  let first_kv = find_map (fun s ->
    match String.split_on_char '=' s with
    | [k; v] -> Some (k, v)
    | _ -> None
  ) env_vars in
  match first_kv with
  | Some (k, v) -> Printf.printf "First valid var: %s=%s\n" k v
  | None -> print_endline "None"