In Rust, collections are used to store and manipulate groups of data. The most common collection types include Vec<T>, HashSet<T>, and HashMap<K, V>. Each type has different characteristics, making them suitable for various scenarios. A Vec<T>, short for vector, is a dynamically-sized array. A HashSet<T> stores unique values of type T, while a HashMap<K, V> stores key-value pairs, with keys of type K and values of type V. In this article, we'll cover how to convert a Vec<T> into a HashSet<T> or a HashMap<T, U>, with clear examples for each conversion.
Table of Contents
Converting Vec<T> to HashSet<T>
One of the most common reasons to convert a Vec into a HashSet is to remove duplicates from the vector. Since a HashSet keeps only unique elements, this is a straightforward conversion.
Here’s an example demonstrating how to perform this conversion:
use std::collections::HashSet;
fn main() {
let vec = vec![1, 2, 2, 3, 4, 4, 5];
let set: HashSet<i32> = vec.into_iter().collect();
println!("HashSet contains: {:?}", set);
}
In this code, into_iter() converts the Vec into an iterator, and collect() constructs a HashSet from the elements of the iterator. The result is a HashSet containing only unique elements: {1, 2, 3, 4, 5}.
Converting Vec<T> to HashMap<T, U>
Converting a Vec<T> to a HashMap<T, U> requires specifying how to derive the key and value for each entry in the HashMap. This generally involves iterating over the elements of the vector and transforming them into key-value pairs.
Suppose we have a vector of tuples, and we want to create a HashMap where the first element of each tuple is the key and the second element is the value. Here’s how you can achieve this:
use std::collections::HashMap;
fn main() {
let vec = vec![("apple", 3), ("banana", 2), ("pear", 5)];
let map: HashMap<&str, i32> = vec.into_iter().collect();
println!("HashMap contains: {:?}", map);
}
Here, into_iter() converts the Vec into an iterator, and collect() constructs a HashMap from the iterator. The resulting map is {"apple": 3, "banana": 2, "pear": 5}.
In some cases, you might have a vector of just values and wish to convert it into a HashMap by deriving keys algorithmically from the values, such as by using the values' indices as keys:
fn main() {
let vec = vec!["alpha", "beta", "gamma"];
let map: HashMap<usize, &str> = vec.iter().enumerate().map(|(i, &val)| (i, val)).collect();
println!("Derived HashMap: {:?}", map);
}
This code uses enumerate() to pair each element with its index, then map() transforms these pairs into the desired key-value pairs for the HashMap. The final map is {0: "alpha", 1: "beta", 2: "gamma"}.
Conclusion
Understanding how to transform between different collection types like Vec<T>, HashSet<T>, and HashMap<K, V> is crucial for efficient data manipulation in Rust. Knowing these conversions allows for better management of data structures, enabling optimized operations like duplicates removal and mapping relationships between data. Leveraging into_iter(), iter(), map(), and collect() generic methods makes these transformations seamless and conveys Rust's expressive power.