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)