Is it possible to detect collisions when collecting into a HashMap?

I want to detect and warn about collisions in the logs when collecting a IntoIterator into a HashMap. The current Rust behavior of collecting into a HashMap is to silently overwrite the earlier values with the latest one.

fn main() {
    let a = vec![(0, 1), (0, 2)];
    let b: std::collections::HashMap<_, _> = a.into_iter().collect();
    println!("{}", b[&0]);
}

Output:

2

(Playground)

A possible workaround is collecting into a Vec then manually writing the conversion code, but that will introduce extra allocation overhead and unreadable code. Not consuming the original collection and comparing the len()s is less noisy, but still hogs 1x more memory (?) and can't detect where exactly the collision is happening.

Is there a more elegent way of handling HashMap collisions?


Solution 1:

Depending on what you want to do in the case of a collision, you might be able to use fold (or try_fold) and the entry API to implement your custom functionality:

use std::collections::HashMap;

fn main() {
    let a = vec![(0, 1), (0, 3), (0, 2)];

    let b: std::collections::HashMap<_, _> = a.into_iter().fold(HashMap::new(), |mut map, (k,v)| {
        map.entry(k)
            .and_modify(|_| println!("Collision with {}, {}!", k, v))
            .or_insert(v);
        map
    });

    println!("{}", b[&0]);
}

(Playground)