I have this function that counts frequencies of case-insensitive-letters of some text.
fn frequency(text: &[&str]) -> HashMap<char, usize> {
let mut freq = HashMap::new();
for line in text {
for ch in line.to_lowercase().chars() {
if ch.is_alphabetic() {
freq.entry(ch).and_modify(|cnt| *cnt += 1).or_insert(1);
}
}
}
freq
}
I want to rewrite this in iterator style. So I (try to) do
text.into_iter()
.flat_map(|line| line.to_lowercase().chars()) // bug!
.filter(|ch| ch.is_alphabetic())
.fold(HashMap::new(), |mut freq, ch| {
freq.entry(ch).and_modify(|cnt| *cnt += 1).or_insert(1);
freq
})
This does not compile because of a reference to temporary value in the closure to flat_map
! Here's one that does compile
text.into_iter()
.fold(HashMap::new(), |freq, line| {
line.to_lowercase()
.chars()
.filter(|ch| ch.is_alphabetic())
.fold(freq, |mut freq, ch| {
freq.entry(ch).and_modify(|cnt| *cnt += 1).or_insert(1);
freq
})
})
but this performs significantly slower than the original loop version.
There were so many claims that iterators would outperform hand rolled loops. Am I missing an angle here?