Reputation: 1832
I want to build a function that counts the number of times an element appears in an array, but I'm being unable to resolve a compile time bug, here is my code
fn vec_count_elem(vec: Vec<int>) -> Vec<int> {
let mut counts: HashMap<int, int> = HashMap::new();;
let mut result: Vec<int>;
for el in vec.iter() {
match counts.find(el) {
Some(count) => {
let new_count: int = count + 1;
counts.remove(el);
counts.insert(*el, new_count)
},
None => counts.insert(*el, 0)
}
}
for value in counts.values() {
result.push(*value);
}
return result;
}
and here is the compile log
/sorting/src/main.rs:40:9: 47:10 error: mismatched types: expected `()`, found `bool` (expected (), found bool)
/sorting/src/main.rs:40 match counts.find(el) {
/sorting/src/main.rs:41 Some(count) => {
/sorting/src/main.rs:42 let new_count: int = count + 1;
/sorting/src/main.rs:43 counts.remove(el);
/sorting/src/main.rs:44 counts.insert(*el, new_count)
/sorting/src/main.rs:45 },
Looking at this example (http://doc.rust-lang.org/std/collections/struct.HashMap.html#example), the counts.find(el) should return the right data type for the match operator
Thank you!
UPDATE1:
The first issue is solved (missing ;
), thank you Arjan!
Now my problem resides with my access inside the match clause to the counts hashmap, I'm getting this error:
sorting/src/main.rs:50:21: 50:27 error: cannot borrow `counts` as mutable because it is also borrowed as immutable
sorting/src/main.rs:50 counts.remove(el);
^~~~~~
sorting/src/main.rs:46:20: 46:26 note: previous borrow of `counts` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `counts` until the borrow ends
Any ideas what is the best way to do this?
Upvotes: 0
Views: 1028
Reputation: 14992
Using the .entry()
method of HashMap, you can make a pretty compact version of it :
use std::collections::hashmap::{HashMap, Occupied, Vacant};
fn vec_count_elem(vec: Vec<int>) -> Vec<int> {
let mut counts: HashMap<int, int> = HashMap::new();
for el in vec.iter() {
match counts.entry(*el) {
Occupied(mut e) => { *e.get_mut() += 1; },
Vacant(mut e) => { e.set(1); }
}
}
return counts.values().map(|i| *i).collect();
}
Upvotes: 4
Reputation: 11
You can do the job after match
statement, as borrowed counts will be released like this:
fn vec_count_elem(vec: Vec<int>) -> Vec<int> {
let mut counts: HashMap<int, int> = HashMap::new();;
let mut result: Vec<int> = vec![];
for el in vec.iter() {
let (el, new_count) = match counts.find(el) {
Some(count) => {
let new_count: int = count + 1;
(*el, new_count)
},
None => (*el, 0),
};
counts.remove(&el);
counts.insert(el, new_count);
}
for value in counts.values() {
result.push(*value);
}
result
}
Also result should be initialized first.
Upvotes: 0
Reputation: 21465
The problem here is that you are returning bool
from the match
and for
is expecting an expression of type ()
. You can solve this by adding ;
after the match:
for el in vec.iter() {
match counts.find(el) {
// ...
};
}
But once you fix this there are other problems with your code:
remove
inside of the match statement because counts
is still borrowed because of the call to find
To fix the second problem replace find
with find_mut
. Unfortunately insertnig in the case of None
does not currently work, but this might change in the future:
for el in vec.iter() {
let found = match counts.find_mut(el) {
Some(count) => {
*count = *count + 1;
true
}
None => false
};
if !found {
counts.insert(*el, 0);
}
}
Simple solution without reconstructing your code is to just replace find
with find_copy
.
Upvotes: 1