Search code examples
rusthashmap

How do I collect the values of a HashMap into a vector?


I can not find a way to collect the values of a HashMap into a Vec in the documentation. I have score_table: HashMap<Id, Score> and I want to get all the Scores into all_scores: Vec<Score>.

I was tempted to use the values method (all_scores = score_table.values()), but it does not work since values is not a Vec.

I know that Values implements the ExactSizeIterator trait, but I do not know how to collect all values of an iterator into a vector without manually writing a for loop and pushing the values in the vector one after one.

I also tried to use std::iter::FromIterator; but ended with something like:

all_scores = Vec::from_iter(score_table.values());
expected type `std::vec::Vec<Score>`
   found type `std::vec::Vec<&Score>`

Thanks to Hash map macro refuses to type-check, failing with a misleading (and seemingly buggy) error message?, I changed it to:

all_scores = Vec::from_iter(score_table.values().cloned());

and it does not produce errors to cargo check.

Is this a good way to do it?


Solution

  • There are three useful methods1 on HashMaps, which all return iterators:

    1. values() borrows the collection and returns references (&T).
    2. values_mut() gives mutable references &mut T which is useful to modify elements of the collection without destroying score_table.
    3. into_values() gives you the elements directly: T! The iterator takes ownership of all the elements. This means that score_table no longer owns them, so you can't use score_table anymore!

    In your example, you call values() to get &T references, then convert them to owned values T via a clone(), which creates potentially expensive copies.


    Instead, if we have an iterator of owned values, then we can convert it to a Vec using Iterator::collect():

    let all_scores: Vec<Score> = score_table.into_values().collect();
    

    Sometimes, you may need to specify the collecting type:

    let all_scores = score_table.into_values().collect::<Vec<Score>>();
    

    1 This is a common pattern in Rust. In the standard library, and popular crates, you'll often find functions with these (into)_thing_(mut) names, with the presence or absence of these functions letting you know what you can do with that object.