Is there a nice way to copy the contents of an entire HashMap to another

I have two HashMaps that will always be the same size (always the same keys, different values). I want to copy the values from the one HashMap to another. Is there a nice way to do this without reallocating a new HashMap?

You can iterate over first HashMap and write the values to the other, you don't need to allocate a temporary HashMap or reallocate the second one if it's capacity is enough.

I think I basically just want an .update() method?

let map1: HashMap<_, _> = // large hashmap contents
let mut map2: HashMap<_, _> = // large hashmap contents

map2.update(&map1). 

Currently I'm just cloning the first map, and dropping the previous one. So I was wondering if there was a better use of memory than the following.

map2 = map1.clone()
use std::collections::HashMap;

fn main() {
    let map1: HashMap<i32, i32> = HashMap::new(); // large hashmap contents
    let mut map2: HashMap<i32, i32> = HashMap::new(); // large hashmap contents

    // overwrite map2 with the contents of map1
    map2.clear();
    map2.extend(map1.into_iter());
    // `map1.into_iter()` consumes map1 and turns it into an iterator
}
2 Likes

You can also write this as:

map2.extend(map1);

If you need to keep map1 around, you can do:

map2.extend(map1.iter().cloned());

This will clone each item in map1 but it will not clone the HashMap itself.

8 Likes

Thanks! This is exactly what I want. Must have missed it in the docs.

You could also use the often forgotten Clone::clone_from, so it would just be map2.clone_from(&map1)

7 Likes

This won’t work. The map’s iterator is over (&K, &V), so .cloned() does not apply.

1 Like

For your setting where your target map already has all the keys, you can avoid needing to re-create all the keys again, whereas both

map2.extend(map1.iter().map(|(k,v)| (k.clone(), v.clone())))

and

map2.clone_from(&map1)

will have to clone every key.

When all the necessary keys are already present, you can work with something like e.g.:

fn try_update_map<K: Eq + Hash, V: Clone>(target: &mut HashMap<K, V>, source: &HashMap<K, V>) -> Option<()> {
    source.iter().try_for_each(|(k, v)| Some(*target.get_mut(k)? = v.clone()))
}

or

fn update_map<K: Eq + Hash, V: Clone>(target: &mut HashMap<K, V>, source: &HashMap<K, V>) {
    source.iter().for_each(|(k, v)| *target.get_mut(k).unwrap() = v.clone())
}

This is probably strictly more performant than anything involving .extend. The .clone_from version could be better when cloning keys is cheap. I’m just guessing though.

7 Likes