Filter HashMap with mutation of elements

I have got a hashmap, which I want to iterate over, mutate some elements, filter out some elements and take remaining keys (or map it to something else). I face compiler error cannot borrow data mutably in a & reference, which I understand why but do not know what to do about it. Could you please suggest what is Rust approach to work with mutable HashMaps using fluent syntax?

Here is the playground

use std::collections::HashMap;

fn main() {
    let mut map: HashMap<String, HashMap<String, String>> = HashMap::new();
    process_mutable_map(&mut map);
}

fn process_mutable_map(map: &mut HashMap<String, HashMap<String, String>>) {
    for (key, value) in map.iter_mut() {
        let a: &mut HashMap<String, String> = value; // here I can take element value as mutable ref
    }

    let res: Vec<String> = map
        .iter_mut()
        .filter(|e| {
// but here I can not take element value as mutable ref, because it is a immutable ref to a tuple !!?
            let element: &mut HashMap<String, String> = e.1;
            // mutate element here, skipped for simplicity
            // assume nothing is taken for simplicity of the example
            false
        })
        .map(|e| e.0.clone())
        .collect();
}

if I can not use filter, I have got the option to use for loop and build vector of remaining keys via some sort of extendable buffer. Using fluent syntax is not possible in this case with HashMap?

I have found a workaround with filter_map() which delivers a tuple to a filter predicate, not a reference to a tuple. I still do not know the reason, why filter() does not have the same predicate function signature?

HashMap has a method retain which can filter out elements. Example:

use std::collections::HashMap;

fn main() {
    let mut map: HashMap<String, HashMap<String, String>> = HashMap::new();
    map.insert("aaa".into(), HashMap::new());
    map.insert("BBB".into(), HashMap::new());
    map.retain(|k, _v| { k.contains('a') });
    println!("{:?}", map);
}

What's more, the type of predicate is FnMut(&K, &mut V) -> bool, which means you can modify the value when you are iterating.

1 Like

filter() returns a bool, whereas filter_map() maps the value to something else. Since filter() only looks at the value, it has to take it by ref so that it wouldn’t try to move it.