0
\$\begingroup\$

I have written a code snippet to use HashMap<String, Vec<&String>> as the main data structure, and finally, I want to return a collected Vec<Vec<String>>, I can archive it by a for-loop, it there any pure iterator way to do this? (I have tried several times, but got tons of confused compiler errors)

pub fn group_anagrams(strs: Vec<String>) -> Vec<Vec<String>> {
    let mut map: HashMap<String, Vec<&String>> = HashMap::new();
    for s in &strs {
        let mut key = s.clone();
        unsafe {
            key.as_bytes_mut().sort();
        }
        (*map.entry(key).or_insert(vec![])).push(s);
    }
    let mut ans: Vec<Vec<String>> = Vec::new();
    // I don't like these 2 lines
    for v in map.values() {
        ans.push(v.iter().cloned().cloned().collect::<Vec<String>>())
    }
    ans
}

I also tried with this code:

    pub fn group_anagrams(strs: Vec<String>) -> Vec<Vec<String>> {
        let mut map: HashMap<String, Vec<String>> = HashMap::new();
        for s in strs {
            let mut key = s.clone();
            unsafe {
                key.as_bytes_mut().sort();
            }
            (*map.entry(key).or_insert(vec![])).push(s);
        }
        map.values().cloned().collect::<Vec<Vec<String>>>()
    }

In the last line, I want to move all the values from hashmap into result vector but also failed because of the lifetime error(then I gave up with a cloned vector), I am wondering how to make it.

\$\endgroup\$
0
\$\begingroup\$
    unsafe {
        key.as_bytes_mut().sort();
    }

This works as long as you are working in Ascii, but will have undefined behavior if there is any unicode in the string.

 (*map.entry(key).or_insert(vec![])).push(s);

You don't need the dereference *, calling a method will automatically take care of that.

Its a bit tricky to help with your main question since I don't know what exactly you tried and why that didn't work.

A pretty direct translation of what you wrote into iterator syntax works:

map.values()
    .map(|v| v.iter().cloned().cloned().collect::<Vec<String>>())
    .collect()

I would however suggest doing something more like your second code block, and avoid cloning the strings:

    map.values().cloned().collect::<Vec<Vec<String>>>()

I'd do this:

 map.into_iter()
    .map(|(_key, values)| values)
    .collect()

By consuming the iterator we avoid cloning the vectors.

Alternatively, take the strings as input by reference and return them by reference:

pub fn group_anagrams(strs: &[String]) -> Vec<Vec<&String>> {
    let mut map: HashMap<String, Vec<&String>> = HashMap::new();
    for s in strs {
        let mut key = s.clone();
        unsafe {
            key.as_bytes_mut().sort();
        }
        (*map.entry(key).or_insert(vec![])).push(s);
    }

    map.into_iter()
        .map(|(_key, values)| values)
        .collect()
}
\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.