- I am writing a "word frequency counter". Here is what I have so far:
pub struct WordFreq {
storage: HashMap<String, usize>,
}
impl WordFreq {
pub fn new() -> WordFreq {
WordFreq { storage: HashMap::new() }
}
pub fn add_word(&mut self, word: &str, n: usize) {
let mut hm = &mut self.storage;
let v = hm.get(word);
let word = word.to_string();
match v {
None => hm.insert(word, n),
Some(old_val) => hm.insert(word, n+old_val),
};
}
}
- In this code, we call
word.to_string()
always. This seems unnecessary in the case when the string already exists in the hashmap. Is there a way to optimize this away?
Use the entry api:
*hm.entry(word).or_insert(0) += 1;
Edit: Dammit, I knew I should have tried this first.
1 Like
The entry
API requires a full key (String
), but you can do a lookup first with the &str
:
pub fn add_word(&mut self, word: &str, n: usize) {
let hm = &mut self.storage;
if let Some(val) = hm.get_mut(word) {
*val += n;
} else {
hm.insert(word.to_string(), n);
}
}
You could also consider using &str
for the keys, if you don't need the map to outlive the source of your strings, and then entry
is easy:
pub struct WordFreq<'a> {
storage: HashMap<&'a str, usize>,
}
impl<'a> WordFreq<'a> {
pub fn new() -> WordFreq<'a> {
WordFreq { storage: HashMap::new() }
}
pub fn add_word(&mut self, word: &'a str, n: usize) {
*self.storage.entry(word).or_insert(0) += n;
}
}
1 Like