I feel rather dumb not being able to solve this by myself.
I have a HashMap where I'd like to modify and maybe remove several entries in order to process them elsewhere.
This is one of several horrible solutions I came up with:
use std::collections::{HashMap, hash_map::Entry};
#[derive(Debug)]
struct SomeObject(u32);
fn main() {
let mut my_map = HashMap::<String, SomeObject>::default();
my_map.insert("xyz".to_string(), SomeObject(123));
my_map.insert("abc".to_string(), SomeObject(321));
// clone(!!) all keys
let keys = my_map.keys().cloned().collect::<Vec<String>>();
// removed objects go here
let mut drained_entries = Vec::new();
for key in keys {
// unnecessary lookup
match my_map.entry(key) {
Entry::Occupied(mut entry) => {
let some_object = entry.get_mut();
some_object.0 -= 1;
if some_object.0 < 200 {
drained_entries.push(entry.remove());
}
}
Entry::Vacant(_entry) => {
//
unreachable!()
}
}
}
println!("retained {:?}", my_map);
println!("drained {:?}", drained_entries);
// prints:
// retained {"abc": SomeObject(320)}
// drained [SomeObject(122)]
}
(playground: Rust Playground )
The following ideas didn't work out:
-
drain()doesn't allow filtering and will remove every entry -
iter_mut()doesn't allow to remove entries -
retain()doesn't allow to move out the value without cloning -
entry()doesn't provide an iterator
If there was something like filter_drain() or occupied_entries() it would be easy to implement without cloning, double lookups, or excessive memory consumption.
Thank you for helping me out!