No matter what programming language you use, finding the index of an element in an array is one of those common processes needed to perform different operations such as updating or removing an element of an array. Hopefully, this article not only gives you the solution but also a solid explanation of how to do it in Rust, especially for those who are new to this programming language.
To find the index of an element in an array in Rust, iterate through the elements of the array using the function iter()
, followed by the position()
function. Finally, use the unwrap()
function to extract the contained value, which is the index of the array element. Let’s look at this implementation in code.
let my_array = ["a", "b", "c"];
let index_element = my_array
.iter()
.position(|&x| x == "b")
.unwrap();
print!("Index of b is {}", index_element);
Table of Contents
Understanding the solution
As previously stated, there are three functions used to find the index of an array element:
- iter()
- position()
- unwrap
The iter()
is a function that generates an Iterator trait which helps to iterate a collection of values by reference such as arrays, slices, vectors, etc. Therefore, the result from using iter()
is an iterator of the type T
, where T
is the reference type of the elements of the array. In the previous example, the referemce types of the elements of the array my_array
is &str
.
Iterators have a wide range of functions available, among them is the position()
function. The position()
function searches for an element in an iterator, returning its index. This function uses a closure that executes against the elements in the iterator until it finds one element that meets the condition and returns true.
let my_array = ["a", "b", "c"];
let index_element = my_array
.iter()
.position(|&x| x == "b");
// in other words, it will run the closure for each
// element of my_array, .i.e.,
// if ("a" == "b") return true; This will return false, get the next element
// if ("b" == "b") return true; This will return true, stop processing other elements
// if ("c" == "b") return true; This won't reach to element "c" as it has previously found an element that meets the condition defined in the closure
The closure passed in the position()
doesn’t necessarily get executed on each element of the array as it will stop processing other elements as soon as it finds one element that meets the condition defined in the closure returning as a result true
.
The position()
function returns a value of type Option<usize>
. This type contains the value of the index of the element in the array, but is not necessarily a numeric type <usize>
. Instead, the value could be Some(index)
. Hence, to extract the value of the type Option
, use the unwrap()
function.
let my_array = ["a", "b", "c"];
let option_index_element = my_array
.iter()
.position(|&x| x == "b");
// At this point, option_index_element = Some(1)
let index_element = option_index_element.unwrap();
// index_element = 1;
Solution that works when finding the index of an element in slices and vectors
This solution works in case you want to find the index of an element in a slice or a vector. As a quick reminder, a vector is a growable array, and a slice is a sequence of elements in a collection.
Below, you should find two examples of finding the index of "b"
in a vector and in a slice.
let my_vector = vec!["a", "b", "c"];
let vector_index_element = my_vector
.iter()
.position(|&x| x == "b")
.unwrap();
println!("Index of b is {} in vector", vector_index_element);
let my_string = String::from("abcdefg");
let my_slice = my_string.as_bytes();
let slice_index_element = my_slice
.iter()
.position(|&x| x == "b".as_bytes()[0])
.unwrap();
println!("Index of b is {} in slice", slice_index_element);
Notice how it is practically the same implementation on a vector. However, when working with a slice of a string, we converted the string character to bytes and modified the closure definition used in the position()
function.
Be careful using unwrap()
function
There can be a scenario where you could be trying to find the index of an element that doesn’t exist in an array. In our example, it could be trying to search for the index of "d"
where the array only has the values ["a", "b", "c"]
.
let my_array = ["a", "b", "c"];
let index_element = my_array
.iter()
.position(|&x| x == "d")
.unwrap(); // <- program panics in here
The position()
function returns an Option<usize>
, which can be either Some(index)
whenever the value exists, or None
whenever the value doesn’t exist.
The problem happens when using the unwrap()
function. The unwrap()
function panics if the value that is trying to extract equals None. Whenever this happens, your code will fail.
Luckily, there are other alternatives besides using unwrap()
in case you are unsure if the element you are searching for the index is part of the array: unwrap_or()
or unwrap_or_else()
. Both unwrap_or()
and unwrap_or_else()
return a default value in case the value is None
.
To use unwrap_or()
function, provide a default value as a parameter.
let index_element = my_array
.iter()
.position(|&x| x == "d")
.unwrap_or(0);
// index_element = 0
To use unwrap_or_else()
, provide a closure returning a default value as a parameter.
let index_element = my_array
.iter()
.position(|&x| x == "d")
.unwrap_or_else(|| 0);
// index_element = 0
Note: By using unwrap_or()
or unwrap_or_else()
we could run into another problem: to automatically default to using an index of a non-related element. In the end, it all comes down to what logic fit best your project.
Using into_iter()
instead of iter()
function
Similar to using iter()
function, there is another function called into_iter()
which you can use to find the index of an element in an array.
On one hand, the iter()
function creates an iterator in which the values are passed by reference. Hence, that is why it is necessary to use &
or borrow expression to access the value of the reference.
let index_element = my_array
.iter()
.position(|&x| x == "d") // &x -> accessing the element value by reference
.unwrap();
The into_iter()
function creates an iterator by value. This means it is no longer necessary to use &
or borrow expression to access the value as the iterator already has the value of the collection, in our case, the array.
let my_array = ["a", "b", "c"];
let option_index_element = my_array
.into_iter()
.position(|x| x == "b") // x -> accessing the element value directly
.unwrap();
Other solution to find index of an element of an array: Using a for
loop
Besides the solution presented above, it is possible to find the index of an array using a traditional for
loop by iterating the array using enumerate()
function found on Iterators, or whenever iter()
function is used in an array.
The enumerate()
function returns an iterator with a pair of i
and val
, where i
is the current index and val
is the current value.
Note: You can assign any variable name to the pair (i, val)
. For instance, in the following snippet of code, x
represents val
.
let mut index = None;
for (i, x) in array.iter().enumerate() {
if x.to_string() == "b" {
index = Some(i);
break;
}
}
println!("index {}", index.unwrap());
Note: Initially, you might think the solution of using the position()
function is better. However, it all comes down to what logic the program needs to run.
Conclusion
All in all, this article showed you different ways to find the index of an element of an array by using some type of iterator trait, either Iterator
or IntoIterator
traits to then access functions such as position()
or enumerate()
in order to define conditional statements to identify the correct element of the array.
Was this article helpful?
I hope this tutorial helped you to clarify doubts and concepts of Rust, especially to those new to the programming language.
Share your thoughts by replying on Twitter of Become A Better Programmer or to personal my Twitter account.