I have a HashMap<String, u32>. Now I would like to remove characters from the String like the following:
#someWord### -> someWord i.e. remove any '#' as prefix or suffix
######### -> if String consists only of '#' remove it from the HashMap
some#Word -> some#Word, i.e do nothing if '#' is in the middle
For option 1 I have found a nice method:
let mut s = String::from("##dog#");
s = s.trim_matches('#').to_string();
However, if I try to put all 3 checks in 1 piece of code it does not work - I am missing something:
As an example I started with:
for (word, _) in words.iter_mut() {
word = &word.trim_matches('#').to_string(); // this is failing due to insufficient lifetime
// some code
words.remove(); // here it fails because I try to change words while iter_mut() is already doing it
Then I've tried t follow this suggestion Stack to have another collection created, but have some troubles with the filter method as it requires a bool expression:
let words: HashMap<_,_> = words.into_iter()
.filter(|&(ref word, _)| // pseudocode -> trim word and if becomes empty, add nothing to the new HashMap )
.collect();
You could resolve this by putting a "map" step before your "filter" step. The "map" step does the word-trimming and returns the (trimmed key, payload) tuple, then the "filter" step eliminates tuples with empty keys.
However, after some tests I realized that it is not working correctly due to the HashMap property to have only 1 key value pair for the same key:
i.e. I cannot have
dog - 4
dog - 9
in a HashMap.
So what would you advise me:
Is it possible to use HashMap to achieve the following:
dog - 1 #dog# - 3
after command:
dog - 4
or should I use other constructors such as Vectors?
A naive way to solve that would be to collect the (trimmed_key, value) pairs in a Vec, sort by key, merge the neighbouring elements and reconstruct the resulting HashMap.
But that has poor memory and computational efficiency, so I would personally prefer something like this:
Create a new HashMap
Loop over the (key, value) pairs of the old map
Trim the key
Check if the new map already contains an entry associated with the trimmed key
If so, add the value to that of the existing entry
If not, create a new entry for that key with the relevant value
HashMap has a nice API for this kind of use case. In addition, one extra advantage of this solution is you can avoid systematically converting each trimmed key to a heap-allocated String, and use just an &str slice in some cases instead.