[Avg. reading time: 8 minutes]
Enumerate()
When iterating over a collection, you often need both the index and the value.
A traditional approach manually manages the index:
fn main() { let fruits = ["apple", "banana", "cherry"]; for i in 0..fruits.len() { println!("Index: {}, Fruit: {}", i, fruits[i]); } }
- You manually manage the range
- You index into the array
- It is more imperative than necessary
Instead of handling i and index positions manually, Rust offers an easier, cleaner, safer technique using Enumerate().
Like iter() enumerate() is also a part of Functional programming.
It transforms any iterator into a new iterator that yields:
(index, value)
The enumerator turns an iterator over elements.
fn main() { let fruits = ["apple", "banana", "cherry"]; for (index, fruit) in fruits.iter().enumerate() { println!("Index: {}, Fruit: {}", index, fruit); } }
- fruits.iter() creates an iterator over references
- enumerate() wraps it
- Each iteration returns a tuple: (usize, &T)
Using enumerate() with Ranges
Using multiple conditions and variables, a loop condition can also be more complex. For example, the for loop can be tracked using enumerate.
fn main() { for (i, j) in (100..120).enumerate() { println!("loop has executed {} times. j = {}", i, j); } }
Ignoring Index position with an _
// _ is a generic placeholder. fn main() { let numbers = [1, 3, 5, 7, 9, 11, 13]; let mut sum = 0; for (_, value) in numbers.iter().enumerate() { sum += value; } println!("{}", sum); }
_ means:
- Intentionally ignore this value
- No unused variable warning
Use cases
- Index Tracking: When you need to know the index of an element while iterating,
enumerate()is handy.
fn main(){ for (i, value) in data.iter().enumerate() { if i == 0 { println!("First element: {}", value); } } }
- Conditional Logic: Sometimes, the logic inside a loop might depend on the element’s index. For example, you might want to skip the first element.
fn main(){ let items = [1,3,4,6,7,8,9,10]; for (i, value) in items.iter().enumerate() { if i % 2 == 0 { println!("Even index: {}", value); } } }
- Debugging: When debugging, knowing the index of an element can help trace or log.
for (i, value) in records.iter().enumerate() {
println!("Record {}: {:?}", i, value);
}
- Data Mapping: When you need to create a new data structure that relies on the index and value from an existing iterable.
fn main(){ let fruits = ["Banana","Apple","Mango"]; let result: Vec<String> = fruits .iter() .enumerate() .map(|(i, f)| format!("{}: {}", i, f)) .collect(); println!("{:?}", result); }