Rust enumerate Example: A Comprehensive Guide
The enumerate
method in Rust is a powerful tool for iterating over a collection while keeping track of the index of each item. This method is particularly useful in scenarios where both the item and its position within the collection are needed.
In this article, we’ll explore how to use enumerate
effectively with practical examples.
What is enumerate
in Rust?
The enumerate
method is part of the Rust Iterator
trait. It transforms an iterator into a new iterator that yields pairs (index, item)
, where:
index
is the zero-based position of the item in the collection.item
is the value of the current element.
Signature
fn enumerate(self) -> Enumerate<Self>
self
: The original iterator.- Returns: An iterator yielding
(usize, T)
tuples, whereusize
is the index, andT
is the item type.
Basic Usage of enumerate
Here’s a simple example to demonstrate how enumerate
works.
fn main() {
let fruits = vec!["apple", "banana", "cherry"];
for (index, fruit) in fruits.iter().enumerate() {
println!("Index: {}, Fruit: {}", index, fruit);
}
}
Output
Index: 0, Fruit: apple
Index: 1, Fruit: banana
Index: 2, Fruit: cherry
Practical Examples
1. Modify Elements Using Index
Use enumerate
to modify elements in a mutable collection based on their index.
fn main() {
let mut numbers = vec![10, 20, 30];
for (index, number) in numbers.iter_mut().enumerate() {
*number += index;
}
println!("{:?}", numbers);
}
Output
[10, 21, 32]
2. Filtering Based on Index
Filter elements based on their index using enumerate
.
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let even_indexed_numbers: Vec<_> = numbers
.iter()
.enumerate()
.filter(|(index, _)| index % 2 == 0)
.map(|(_, &num)| num)
.collect();
println!("{:?}", even_indexed_numbers);
}
Output
[1, 3, 5]
3. Working with Strings
Use enumerate
to iterate over characters in a string with their indices.
fn main() {
let word = "Rust";
for (index, char) in word.chars().enumerate() {
println!("Index: {}, Char: {}", index, char);
}
}
Output
Index: 0, Char: R
Index: 1, Char: u
Index: 2, Char: s
Index: 3, Char: t
4. Nested Loops with enumerate
Handle nested loops where indices are important for both levels.
fn main() {
let matrix = vec![
vec![1, 2, 3],
vec![4, 5, 6],
vec![7, 8, 9],
];
for (row_index, row) in matrix.iter().enumerate() {
for (col_index, value) in row.iter().enumerate() {
println!("Row: {}, Col: {}, Value: {}", row_index, col_index, value);
}
}
}
Output
Row: 0, Col: 0, Value: 1
Row: 0, Col: 1, Value: 2
Row: 0, Col: 2, Value: 3
Row: 1, Col: 0, Value: 4
Row: 1, Col: 1, Value: 5
Row: 1, Col: 2, Value: 6
Row: 2, Col: 0, Value: 7
Row: 2, Col: 1, Value: 8
Row: 2, Col: 2, Value: 9
Common Use Cases for enumerate
- Debugging:
- Print the index and value of each element in a collection for troubleshooting.
- Index-Based Operations:
- Perform calculations or modifications based on the position of elements.
- Data Transformation:
- Map elements along with their indices into a new structure.
- Filtering:
- Select elements based on their index or a combination of index and value.
Best Practices
- Use
.iter_mut()
for Mutable Iterators:- Use
.iter_mut()
withenumerate
when modifying elements in a collection.
- Use
- Destructure Tuples for Clarity:
- Clearly destructure
(index, value)
pairs for readability.
- Clearly destructure
- Combine with Other Iterator Methods:
- Chain
enumerate
with methods likefilter
,map
, orcollect
for powerful transformations.
- Chain
- Avoid Manual Index Tracking:
- Instead of manually maintaining an index variable, use
enumerate
for cleaner and safer code.
- Instead of manually maintaining an index variable, use
Conclusion
Rust’s enumerate
method is a versatile tool for iterating over collections while keeping track of indices. It simplifies many tasks by eliminating the need for manual index tracking and integrates seamlessly with Rust’s iterator ecosystem. By mastering enumerate
, you can write cleaner, more efficient, and more expressive code.