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

270: Finding Index with position()

Difficulty: 1 Level: Beginner Find the zero-based index of the first element satisfying a predicate โ€” returns `Option<usize>`.

The Problem This Solves

You need to know where something is, not just whether it exists. The insertion point for a binary search result. The index at which to split a slice. The column number of the first error in a row. `find()` gives you the value; `position()` gives you the index โ€” and indexes let you do things that values alone don't: slice the array, compute an offset, build an error message with a position. Without `position()`, you'd use `enumerate()` + `find()` and then destructure the result โ€” three operations instead of one. Or you'd write a manual loop with a counter. `position()` is the direct answer to "at what index is the first X?". In OCaml, you'd write `let rec find_pos pred i = function [] -> None | x :: xs -> if pred x then Some i else find_pos pred (i+1) xs`. In Rust, `position()` is a one-liner.

The Intuition

`position(pred)` returns `Some(index)` where `index` is the zero-based position of the first element for which the predicate returns `true`, or `None` if no element matches.
let nums = [10, 20, 30, 40, 50];
let idx = nums.iter().position(|&x| x > 25);
// โ†’ Some(2)  (first element > 25 is 30, at index 2)

How It Works in Rust

let nums = [10i32, 20, 30, 40, 50];

// Basic: find index of first match
let idx = nums.iter().position(|&x| x > 25);
// โ†’ Some(2)

// With pattern matching
let words = ["apple", "banana", "cherry", "date"];
match words.iter().position(|&w| w == "cherry") {
 Some(i) => println!("'cherry' at index {}", i),  // โ†’ 2
 None    => println!("Not found"),
}

// Use index to slice around the found element
if let Some(split) = nums.iter().position(|&x| x == 30) {
 let before = &nums[..split];    // โ†’ [10, 20]
 let after  = &nums[split+1..];  // โ†’ [40, 50]
}

// rposition: search from the right
let data = [1i32, 2, 3, 2, 1];
let first = data.iter().position(|&x| x == 2);   // โ†’ Some(1)
let last  = data.iter().rposition(|&x| x == 2);  // โ†’ Some(3)

// Chain with map for a formatted message
let message = nums.iter()
 .position(|&x| x >= 35)
 .map(|i| format!("Found {} at index {}", nums[i], i))
 .unwrap_or_else(|| "Not found".to_string());
`position()` consumes the iterator up to (and including) the found element. Use `rposition()` on slices to search from the right.

What This Unlocks

Key Differences

ConceptOCamlRust
Find index by predicateManual recursion with counter`iter.position(pred)`
Search from rightManual recursion`slice.rposition(pred)`
Returns`int option``Option<usize>`
vs. `find()``find` returns the value`position` returns the index
vs. `enumerate().find()`Equivalent but verbose`position()` is the direct shortcut
//! 270. Finding index with position()
//!
//! `position(pred)` returns `Option<usize>` โ€” index of first element where predicate holds.

fn main() {
    let nums = [10i32, 20, 30, 40, 50];

    let idx = nums.iter().position(|&x| x > 25);
    println!("First >25 at index: {:?}", idx);

    let words = ["apple", "banana", "cherry", "date"];
    match words.iter().position(|&w| w == "cherry") {
        Some(i) => println!("'cherry' at index {}", i),
        None    => println!("Not found"),
    }

    if let Some(split) = nums.iter().position(|&x| x == 30) {
        println!("Before 30: {:?}", &nums[..split]);
        println!("After 30:  {:?}", &nums[split+1..]);
    }

    let data = [1i32, 2, 3, 2, 1];
    let first = data.iter().position(|&x| x == 2);
    let last  = data.iter().rposition(|&x| x == 2);
    println!("First 2: {:?}, Last 2: {:?}", first, last);

    let message = nums.iter()
        .position(|&x| x >= 35)
        .map(|i| format!("Found {} at index {}", nums[i], i))
        .unwrap_or_else(|| "Nothing >= 35".to_string());
    println!("{}", message);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_position_found() {
        let v = [10i32, 20, 30, 40];
        assert_eq!(v.iter().position(|&x| x == 30), Some(2));
    }

    #[test]
    fn test_position_not_found() {
        let v = [1i32, 2, 3];
        assert_eq!(v.iter().position(|&x| x == 99), None);
    }

    #[test]
    fn test_rposition() {
        let v = [1i32, 2, 3, 2, 1];
        assert_eq!(v.iter().rposition(|&x| x == 2), Some(3));
    }

    #[test]
    fn test_position_first_occurrence() {
        let v = [5i32, 5, 5];
        assert_eq!(v.iter().position(|&x| x == 5), Some(0));
    }
}
(* 270. Finding index with position() - OCaml *)

let position pred lst =
  let rec aux i = function
    | [] -> None
    | x :: xs -> if pred x then Some i else aux (i + 1) xs
  in
  aux 0 lst

let () =
  let nums = [10; 20; 30; 40; 50] in
  (match position (fun x -> x > 25) nums with
  | Some i -> Printf.printf "First >25 at index %d\n" i
  | None -> print_endline "Not found");

  let words = ["apple"; "banana"; "cherry"] in
  (match position (fun w -> w = "banana") words with
  | Some i -> Printf.printf "banana at index %d\n" i
  | None -> print_endline "Not found");

  (match position (fun x -> x = 30) nums with
  | Some i ->
    let before = List.filteri (fun j _ -> j < i) nums in
    Printf.printf "Before 30: %s\n"
      (String.concat ", " (List.map string_of_int before))
  | None -> print_endline "30 not found")