In Scala, there is a method named toMap
that works on any list of tuples and converts it to a map where the key is the first item on the tuple and the value is the second one:
val listOfTuples = List(("one", 1), ("two", 2)) val map = listOfTuples.toMap
What is the closest thing to toMap
in Rust?
Use Iterator::collect
:
use std::collections::HashMap; fn main() { let tuples = [("one", 1), ("two", 2), ("three", 3)]; let m: HashMap<_, _> = tuples.into_iter().collect(); println!("{:?}", m); }
collect
leverages the FromIterator
trait. Any iterator can be collected into a type that implements FromIterator
. In this case, HashMap
implements it as:
impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S> where K: Eq + Hash, S: HashState + Default,
Said another way, any iterator of tuples where the first value can be hashed and compared for total equality can be converted to a HashMap
. The S
parameter isn't exciting to talk about, it just defines what the hashing method is.
With this knowledge, you can also call FromIterator
directly:
use std::collections::HashMap; fn main() { let m: HashMap<_, _> = HashMap::from_iter([("one", 1), ("two", 2), ("three", 3)]); println!("{:?}", m); }
See also:
what change should I make so that I get all the values with same key stored in a
Vec
?
There's no one-line / functional method for this in the standard library. Instead, use the entry
API:
use std::collections::HashMap; fn main() { let tuples = vec![("one", 1), ("two", 2), ("one", 3)]; let mut m = HashMap::new(); for (k, v) in tuples { m.entry(k).or_insert_with(Vec::new).push(v) } println!("{:?}", m); }
If you found yourself doing this frequently, you could create your own type and implement FromIterator
for it:
use std::{cmp::Eq, collections::HashMap, hash::Hash, iter::FromIterator}; struct MyCoolType<K: Eq + Hash, V>(HashMap<K, Vec<V>>); impl<K: Eq + Hash, V> FromIterator<(K, V)> for MyCoolType<K, V> { fn from_iter<I>(tuples: I) -> Self where I: IntoIterator<Item = (K, V)>, { let mut m = HashMap::new(); for (k, v) in tuples { m.entry(k).or_insert_with(Vec::new).push(v) } Self(m) } } fn main() { let tuples = vec![("one", 1), ("two", 2), ("one", 3)]; let MyCoolType(m) = tuples.into_iter().collect(); println!("{:?}", m); }
See also:
Since it wasn't already mentioned, here is a single line (albeit long) method:
use std::collections::HashMap; fn main() { let m: HashMap<&str, u16> = [("year", 2019), ("month", 12)].iter().cloned().collect(); println!("{:?}", m); }
Or you can do a Trait:
use std::collections::HashMap; trait Hash { fn to_map(&self) -> HashMap<&str, u16>; } impl Hash for [(&str, u16)] { fn to_map(&self) -> HashMap<&str, u16> { self.iter().cloned().collect() } } fn main() { let m = [("year", 2019), ("month", 12)].to_map(); println!("{:?}", m) }
https://doc.rust-lang.org/std/collections/struct.HashMap.html#examples
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With