270: Finding Index with position()
Functional Programming
Tutorial
The Problem
Locating the position of an element matching a condition is a fundamental operation: finding where a token appears in a list, locating a delimiter in a byte sequence, or finding the insertion point in a sorted array. Unlike find() which returns the element, position() returns the zero-based index — essential when the index itself is needed for slicing, bounds computation, or further navigation.
🎯 Learning Outcomes
position(pred) returns Option<usize> — the index of the first matching elementposition() from find(): index vs element valuerposition() to find the last matching index from the right (on slices)position() consumes up to the matching element and stopsCode Example
#![allow(clippy::all)]
//! 270. Finding index with position()
//!
//! `position(pred)` returns `Option<usize>` — index of first element where predicate holds.
#[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));
}
}Key Differences
Option<usize> (index only); OCaml 4.14's Array.find_index returns Option<int * 'a> (index and element).position() is built into Rust's Iterator; OCaml required manual implementation or recent library additions.rposition() is available on slice iterators; OCaml requires List.rev then find_index or a right fold.OCaml Approach
OCaml's List.find_index (recent versions) or a manual fold:
let position pred lst =
let rec go i = function
| [] -> None
| x :: xs -> if pred x then Some i else go (i+1) xs
in go 0 lst
For arrays, Array.find_index (OCaml 4.14+) returns Option<int * 'a> with both index and element.
Full Source
#![allow(clippy::all)]
//! 270. Finding index with position()
//!
//! `position(pred)` returns `Option<usize>` — index of first element where predicate holds.
#[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));
}
}
✓ Tests
Rust test suite
#[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));
}
}
Exercises
position().position() to split a string at the first occurrence of ":" — return None if no colon is found.position() iteratively on a shrinking sub-slice, collecting all indices.