Nickolay
Nickolay

Reputation: 32071

Get the Vec of owned values from a HashMap

An algorithm I wrote builds a temporary HashMap. Once it's finished, I'm only interested in the values of the hashmap, so I'd like to transfer ownership of the values from the HashMap<K, V> to a Vec<V>.

With a simplified example hashmap:

fn main() {
    use std::collections::HashMap;
    let mut h: HashMap<_, _> = HashMap::new();
    h.insert(1, "foo".to_owned());
}

I can do:

The actual values are a mid-sized struct ({String, Vec<String>}, under a KB total).

Should I default to avoiding clone in this case or is it premature optimization? Is there an idiomatic way to do this that I'm missing?

Upvotes: 1

Views: 1630

Answers (2)

remykarem
remykarem

Reputation: 2490

Note that as of Rust 1.54.0, the into_values method has been implemented for HashMap and BTreeMap in the standard library.

fn main() {
    let mut h: HashMap<i32, String> = HashMap::new();
    h.insert(1, "foo".to_owned());
    let _vals: Vec<String> = h.into_values().collect();
}

https://github.com/rust-lang/rust/blob/master/RELEASES.md#stabilized-apis-6

Upvotes: 2

Stargateur
Stargateur

Reputation: 26765

.into_iter().map(|(_, v)| v) is the idiomatic way to do it. That not ugly at all.

If you want you could do:

use std::collections::hash_map;
use std::collections::HashMap;
use std::iter::{ExactSizeIterator, FusedIterator};

struct IntoValues<K, V> {
    iter: hash_map::IntoIter<K, V>,
}

impl<K, V> IntoValues<K, V> {
    fn new(map: HashMap<K, V>) -> Self {
        Self {
            iter: map.into_iter(),
        }
    }
}

impl<K, V> Iterator for IntoValues<K, V> {
    type Item = V;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(_, v)| v)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}
impl<K, V> ExactSizeIterator for IntoValues<K, V> {}

impl<K, V> FusedIterator for IntoValues<K, V> {}

trait HashMapTool {
    type IntoValues;
    type Item;
    fn into_values(self) -> Self::IntoValues;
}

impl<K, V> HashMapTool for HashMap<K, V> {
    type Item = V;
    type IntoValues = IntoValues<K, V>;
    fn into_values(self) -> Self::IntoValues {
        IntoValues::new(self)
    }
}

fn main() {
    let mut h: HashMap<_, _> = HashMap::new();
    h.insert(1, "foo".to_owned());

    let _vals: Vec<_> = h.into_values().collect();
}

Upvotes: 3

Related Questions