ExamplesBy LevelBy TopicLearning Paths
258 Intermediate

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

  • • Understand how enumerate() wraps each element with its zero-based index
  • • Use (index, value) destructuring patterns in map() and for loops
  • • Filter or transform elements based on their position
  • • Combine enumerate() with filter() to find the index of a matching element
  • Code 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

  • Built-in vs manual: Rust provides enumerate() as a first-class adapter; OCaml requires List.mapi or a manual index counter for the same effect.
  • Zero-based index: Both languages use zero-based indexing for this operation.
  • Type: Rust yields (usize, &T); OCaml's mapi yields the result of the applied function directly.
  • Laziness: 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

  • Use enumerate() to find the index of the first element in a slice that satisfies a predicate, returning Option<usize>.
  • Build a function that takes a Vec<String> and returns a formatted numbered list like ["1. first", "2. second"].
  • Use enumerate() and filter() together to return only the even-indexed elements of a slice.
  • Open Source Repos