1
\$\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.

asked Apr 11, 2021 at 3:24
\$\endgroup\$

1 Answer 1

1
\$\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()
}
answered Apr 11, 2021 at 4:00
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.