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.
1 Answer 1
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()
}