# Having an `Option<T>` as HashMap key is it possible?

Hello everyone! I'm back with another beginner question!
So, this time the error is inside the `count_votes` method in two different lines.
This method tries to count the the frequency of the different votes inside of `total_votes` using a `HashMap`.
The map is filled up with `Option<T>` votes as keys associated to `usize` counters values. The counters increments every time a vote repeats. It's a pretty standard algorithm.
Then `count_votes` returns the most frequent vote wrapped inside a `Ok(Scrutiny())` instance.

Here is the code:

``````pub struct Election<T> {
pub voters: HashMap<&'static str, Option<T>>,
pub winner_threshold: u32,
}

impl<T> Election<T> {
pub fn new(voters: &[&'static str], winner_threshold: u32) -> Election<T> {
let voters: HashMap<&'static str, Option<T>> = (*voters).iter()
.map(|&v| (v, None))
.collect();
Election { voters, winner_threshold, }
}

pub fn vote(&mut self, voter: &'static str, vote: T) {
if let Some(voter) = self.voters.get_mut(voter) {
voter.get_or_insert(vote);
}
}

pub fn count_votes(self) -> Result<Scrutiny<T>, Election<T>> {
.count();
if unvoted > 0 {
Err(self)
} else {
let mut votes_counter: HashMap<Option<T>, usize> = new();
// this line has a compile error
*vote_count += 1;
}
// this line has a compile error
let result = votes_counter.iter().max_by(|&(k, v)| *v);
Ok(Scrutiny { result })
}
}
}

pub struct Scrutiny<T> {
result: T,
}

impl<T> Scrutiny<T> {
pub fn result(&self) -> &T {
&self.result
}
}

``````

The first error that I encountered, and that I don't know if I'm not setting properly the pointer level of `votes_counter` or just `HashMap` can't use Some(T) as keys, is the following:

``````error[E0599]: no method named `entry` found for struct `std::collections::HashMap<std::option::Option<T>, usize>` in the current scope
--> src/core/election.rs:37:48
|
37  |                   let vote_count = votes_counter.entry(vote).or_insert(0);
|
= note: the method `entry` exists but the following trait bounds were not satisfied:
`std::option::Option<T>: std::cmp::Eq`
`std::option::Option<T>: std::hash::Hash`
``````

And the second one, I think it must be an iterator issue that I unable to solve due to my short experience using them. I've tried different approaches going back and forth but I haven't seen the light at the end of the tunnel yet.

``````error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument
--> src/core/election.rs:41:40
|
41 | ...                   .max_by(|&(k, v)| *v);
|                        ^^^^^^ --------- takes 1 argument
|                        |
|                        expected closure that takes 2 arguments
``````

Thank you very much for your time to review my code.

You need to specify that `T` can be hashed and compared to use it as the key.

``````pub fn count_votes(self) -> Result<Scrutiny<T>, Election<T>>
where
T: Eq + Hash,
{
...
}
``````

You can also put the where bound on the impl block.

Note that you should probably be using `String` instead of `&'static str`. The `&'static str` type can only be used with string literals that are hard-coded in your codebase.

2 Likes

Thanks @alice ! awesome fix! I've just tried it out and it enabled me to go further. However, I still have an issue and I think it might be related to how Option is referenced.

``````--> src/core/election.rs:42:54
|
42 |                 let vote_count = votes_counter.entry(vote).or_insert(0);
|                                                      ^^^^
|                                                      |
|                                                      expected enum `std::option::Option`, found reference
|                                                      help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `vote.as_ref()`
|
= note:   expected enum `std::option::Option<T>`
found reference `&std::option::Option<T>`
``````

In fact, I've tried to replace `vote` for `*vote` and `vote.as_ref()` but both alternatives throw errors. I have the impression that I'm not deeply understanding the ownership rule here. Would you have any clue what the problem is here?

ps: Great catch on the `String` to replace `&'static str`. I've already put it in place. Thanks again.

You have to give `entry` an owned value to use it. To do this, you can clone it. The `*vote` did not work because `T` is not necessarily cheaply cloneable. It is a bit unfortunate to make a clone in this case, so I recommend that you instead use `get_mut` combined with `insert`.

``````if let Some(val) = votes_counter.get_mut(&vote) {
*val += 1;
} else {
}
``````
2 Likes

Very accurate. Many thanks @alice I'll just add a small detail to your answer: `T` must implement `Clone` trait to copy `vote`.

Final implementation:

``````use std::collections::HashMap;
use std::hash::Hash;

pub struct Election<T> {
pub voters: HashMap<String, Option<T>>,
}

impl<T> Election<T> {
pub fn new(voters: &[String]) -> Election<T> {
let voters: HashMap<String, Option<T>> = (*voters).iter()
.map(|v| (v.clone(), None))
.collect();
Election { voters, }
}

pub fn vote(&mut self, voter: &String, vote: T) {
if let Some(voter) = self.voters.get_mut(voter) {
voter.get_or_insert(vote);
}
}

pub fn count_votes(self) -> Result<Scrutiny<T>, Election<T>>
where T:
Eq + Hash + Clone,
{
let unvoted = self.voters.values()
.filter(|v| !v.is_some())
.count();
if unvoted > 0 {
Err(self)
} else {
let mut votes_counter = HashMap::<Option<T>, usize>::new();
for vote in self.voters.values() {
if let Some(val) = votes_counter.get_mut(&vote) {
*val += 1;
} else {
}
}
}
}
}

pub struct Scrutiny<T> {
result: HashMap::<Option<T>, usize>,
}

impl<T> Scrutiny<T> {
pub fn result(&self) -> &HashMap::<Option<T>, usize> {
&self.result
}
}
``````

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.