258: Index-Value Pairs with enumerate()
Functional Programming
Tutorial
The Problem
Knowing the position of each element while iterating is a recurring need: numbering output lines, finding the index of the first matching element, or computing index-dependent transformations. The traditional C-style for (int i = 0; i < n; i++) loop provides this but loses the iterator abstraction. The enumerate() adapter solves this by injecting a zero-based index alongside each element, keeping the pipeline composable.
🎯 Learning Outcomes
enumerate() wraps each element with its zero-based index(index, value) destructuring patterns in map() and for loopsenumerate() with filter() to find the index of a matching elementCode Example
#![allow(clippy::all)]
//! 258. Index-value pairs with enumerate()
//!
//! `enumerate()` adds a zero-based index to every iterator element.
#[cfg(test)]
mod tests {
#[test]
fn test_enumerate_indices() {
let v = ["a", "b", "c"];
let indices: Vec<usize> = v.iter().enumerate().map(|(i, _)| i).collect();
assert_eq!(indices, vec![0, 1, 2]);
}
#[test]
fn test_enumerate_values() {
let v = [10i32, 20, 30];
let result: Vec<i32> = v
.iter()
.enumerate()
.map(|(i, &val)| val + i as i32)
.collect();
assert_eq!(result, vec![10, 21, 32]);
}
#[test]
fn test_enumerate_filter_even() {
let v = ["a", "b", "c", "d"];
let even: Vec<_> = v
.iter()
.enumerate()
.filter(|(i, _)| i % 2 == 0)
.map(|(_, v)| *v)
.collect();
assert_eq!(even, vec!["a", "c"]);
}
}Key Differences
enumerate() as a first-class adapter; OCaml requires List.mapi or a manual index counter for the same effect.(usize, &T); OCaml's mapi yields the result of the applied function directly.enumerate() is lazy in Rust; List.mapi processes eagerly in OCaml.OCaml Approach
OCaml's List.mapi applies a function (index -> element -> result) to each element, which is the direct equivalent for transformation. For filtering by position, one typically uses a manual fold_left with a counter accumulator:
let indexed = List.mapi (fun i x -> (i, x)) ["a"; "b"; "c"]
(* [(0,"a"); (1,"b"); (2,"c")] *)
OCaml lacks a direct enumerate() on Seq, but Seq.zip (Seq.ints 0) seq achieves the same lazily.
Full Source
#![allow(clippy::all)]
//! 258. Index-value pairs with enumerate()
//!
//! `enumerate()` adds a zero-based index to every iterator element.
#[cfg(test)]
mod tests {
#[test]
fn test_enumerate_indices() {
let v = ["a", "b", "c"];
let indices: Vec<usize> = v.iter().enumerate().map(|(i, _)| i).collect();
assert_eq!(indices, vec![0, 1, 2]);
}
#[test]
fn test_enumerate_values() {
let v = [10i32, 20, 30];
let result: Vec<i32> = v
.iter()
.enumerate()
.map(|(i, &val)| val + i as i32)
.collect();
assert_eq!(result, vec![10, 21, 32]);
}
#[test]
fn test_enumerate_filter_even() {
let v = ["a", "b", "c", "d"];
let even: Vec<_> = v
.iter()
.enumerate()
.filter(|(i, _)| i % 2 == 0)
.map(|(_, v)| *v)
.collect();
assert_eq!(even, vec!["a", "c"]);
}
}
✓ Tests
Rust test suite
#[cfg(test)]
mod tests {
#[test]
fn test_enumerate_indices() {
let v = ["a", "b", "c"];
let indices: Vec<usize> = v.iter().enumerate().map(|(i, _)| i).collect();
assert_eq!(indices, vec![0, 1, 2]);
}
#[test]
fn test_enumerate_values() {
let v = [10i32, 20, 30];
let result: Vec<i32> = v
.iter()
.enumerate()
.map(|(i, &val)| val + i as i32)
.collect();
assert_eq!(result, vec![10, 21, 32]);
}
#[test]
fn test_enumerate_filter_even() {
let v = ["a", "b", "c", "d"];
let even: Vec<_> = v
.iter()
.enumerate()
.filter(|(i, _)| i % 2 == 0)
.map(|(_, v)| *v)
.collect();
assert_eq!(even, vec!["a", "c"]);
}
}
Exercises
enumerate() to find the index of the first element in a slice that satisfies a predicate, returning Option<usize>.Vec<String> and returns a formatted numbered list like ["1. first", "2. second"].enumerate() and filter() together to return only the even-indexed elements of a slice.