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

272: One-Level Flattening with flatten()

Difficulty: 2 Level: Intermediate Collapse exactly one level of iterator nesting โ€” `Vec<Vec<T>>` โ†’ `Vec<T>`, `Option<Option<T>>` โ†’ `Option<T>`.

The Problem This Solves

After a `map()` that produces a collection per element, or after a series of operations that produce `Option<Option<T>>` or `Vec<Option<T>>`, you end up with a nested structure you need to unwrap by one level. You could `collect()` and then iterate again, but that allocates an intermediate collection. You could use `flat_map` with `|x| x` โ€” which works but looks redundant. `flatten()` is the explicit, zero-overhead way to say "remove one layer of nesting." It's the monadic `join` operation โ€” if `flat_map` is `bind`, `flatten` is `join`. It also works on `Option<Option<T>>` and `Result<Result<T, E>, E>` directly โ€” not just iterators โ€” making it useful for nested fallible operations.

The Intuition

`flatten()` takes an iterator where each item is itself iterable, and concatenates all the inner iterables into one flat sequence. It removes exactly one level โ€” no more.
let nested = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
let flat: Vec<i32> = nested.into_iter().flatten().collect();
// โ†’ [1, 2, 3, 4, 5, 6]

How It Works in Rust

// Flatten Vec<Vec<T>>
let nested = vec![vec![1i32, 2], vec![3, 4], vec![5, 6]];
let flat: Vec<i32> = nested.into_iter().flatten().collect();
// โ†’ [1, 2, 3, 4, 5, 6]

// Flatten iterator of Options โ€” None values are simply skipped
let opts: Vec<Option<i32>> = vec![Some(1), None, Some(3), None, Some(5)];
let values: Vec<i32> = opts.into_iter().flatten().collect();
// โ†’ [1, 3, 5]

// flatten() vs flat_map โ€” equivalent
let text = "hello world\nfoo bar baz\nrust";
let words_via_flatten: Vec<&str> = text.lines()
 .map(|line| line.split_whitespace())   // Iterator<Item=SplitWhitespace>
 .flatten()                              // flatten one level
 .collect();
// equivalent to: text.lines().flat_map(|line| line.split_whitespace())

// Option flattening (not iterator โ€” on Option itself)
let nested_opt: Option<Option<i32>> = Some(Some(42));
assert_eq!(nested_opt.flatten(), Some(42));

let none_inner: Option<Option<i32>> = Some(None);
assert_eq!(none_inner.flatten(), None);
`flatten()` only removes one level. For `Vec<Vec<Vec<T>>>` you'd call `flatten()` twice or restructure your data.

What This Unlocks

Key Differences

ConceptOCamlRust
Flatten one level`List.flatten` / `List.concat``iter.flatten()`
LazyNo (strict)Yes
Works on `Option``Option.join` (not in stdlib)`Option::flatten()` built-in
vs. `flat_map``concat_map f = map f >> flatten``flat_map(f)` = `.map(f).flatten()`
DepthExactly one levelExactly one level
//! 272. One-level flattening with flatten()
//!
//! `flatten()` removes exactly one level of iterator nesting.

fn main() {
    let nested = vec![vec![1i32, 2], vec![3, 4], vec![5, 6]];
    let flat: Vec<i32> = nested.into_iter().flatten().collect();
    println!("Flattened: {:?}", flat);

    // Flatten Option<Option<T>>
    let opt_opt: Option<Option<i32>> = Some(Some(42));
    println!("Some(Some(42)).flatten() = {:?}", opt_opt.flatten());
    println!("Some(None).flatten() = {:?}", Some(None::<i32>).flatten());
    println!("None.flatten() = {:?}", None::<Option<i32>>.flatten());

    // Flatten iterator of Options
    let opts: Vec<Option<i32>> = vec![Some(1), None, Some(3), None, Some(5)];
    let values: Vec<i32> = opts.into_iter().flatten().collect();
    println!("Option values: {:?}", values);

    // Flatten text lines into words
    let text = "hello world
foo bar baz
rust";
    let words: Vec<&str> = text.lines()
        .map(|line| line.split_whitespace())
        .flatten()
        .collect();
    println!("All words: {:?}", words);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_flatten_vec_vec() {
        let nested = vec![vec![1i32, 2], vec![3, 4]];
        let flat: Vec<i32> = nested.into_iter().flatten().collect();
        assert_eq!(flat, vec![1, 2, 3, 4]);
    }

    #[test]
    fn test_flatten_option() {
        assert_eq!(Some(Some(42i32)).flatten(), Some(42));
        assert_eq!(Some(None::<i32>).flatten(), None);
        assert_eq!(None::<Option<i32>>.flatten(), None);
    }

    #[test]
    fn test_flatten_options_in_iter() {
        let v: Vec<Option<i32>> = vec![Some(1), None, Some(3)];
        let result: Vec<i32> = v.into_iter().flatten().collect();
        assert_eq!(result, vec![1, 3]);
    }
}
(* 272. One-level flattening with flatten() - OCaml *)

let () =
  let nested = [[1; 2]; [3; 4]; [5; 6]] in
  let flat = List.concat nested in
  Printf.printf "Flattened: %s\n"
    (String.concat ", " (List.map string_of_int flat));

  let words = ["hello"; "world"] in
  let all_chars = List.concat_map
    (fun w -> List.init (String.length w) (fun i -> w.[i]))
    words in
  Printf.printf "Chars: %s\n"
    (String.concat " " (List.map (String.make 1) all_chars));

  let opts = [Some 1; None; Some 3; None; Some 5] in
  let values = List.filter_map Fun.id opts in
  Printf.printf "Option values: %s\n"
    (String.concat ", " (List.map string_of_int values))