Start learning free

LESSON 141 OF 679 · DICTIONARIES - CHALLENGES

Count a Vote in Rust: get with a Default

Practice Read the full explanation

You get votes, a HashMap from names to how many votes each person has. You also get the name on a new vote.

Count the new vote and return votes.

The person called name gets one more vote. A name with no votes yet isn't in votes. It starts from 0, so after this vote it has 1. The order of the entries doesn't matter.

 

Example 1:

Input: votes = {"Ana": 3, "Ben": 5}, name = "Ana"
Output: {"Ana": 4, "Ben": 5}
Explanation: Ana had 3 votes. Now she has 3 + 1 = 4.

Example 2:

Input: votes = {"Ana": 3, "Ben": 5}, name = "Cara"
Output: {"Ana": 3, "Ben": 5, "Cara": 1}
Explanation: Cara had no votes yet. She starts from 0 and now has 1.

Example 3:

Input: votes = {}, name = "Max"
Output: {"Max": 1}
Explanation: This is the very first vote. Max now has 1.

 

Constraints:

  • votes can be empty.
  • Every count in votes is at least 1.
  • Names are single words made of English letters.
STEP 1 OF 3
    Ctrl + Enter to check

    RUST · DICTIONARIES - CHALLENGES

    Count A Vote in Rust, explained

    Problem overview

    The function count_vote receives votes, a HashMap from names to how many votes each person has, and the name on a new vote. It gives that person one more vote and returns the map. A name with no votes yet isn't in the map: it starts from 0, so after this vote it has 1. The order of the entries doesn't matter.

    With {"Ana": 3, "Ben": 5} and "Ana", Ana goes to 4. With the same map and "Cara", a new key appears with 1 vote. With an empty map and "Max", the very first vote gives {"Max": 1}.

    Approach

    Both cases, a known name and a new name, follow one rule: new count = old count + 1, where the old count of a missing name is 0. So do not branch at all. Read the old count with a default of 0, add 1, and store it back. insert adds the key when it's new and replaces the value when it exists.

    Step by step

    1. Read the current count into count. Look the name up with votes.get(&name), which gives an Option: Some reference for a known name and None for a new one. Apply unwrap_or(&0) to take the reference or fall back on a reference to 0, and put * in front to read the number behind it as a plain i32.
    2. Call votes.insert(name, count + 1). For a new name this adds the key with 1 vote. For a known name it replaces the old count. Since get only borrowed name, the string can move into the map here.
    3. Return votes. Only one entry changed.

    The solution in Rust

    impl Solution {
        fn count_vote(mut votes: HashMap<String, i32>, name: String) -> HashMap<String, i32> {
            let count = *votes.get(&name).unwrap_or(&0);
            votes.insert(name, count + 1);
            return votes;
        }
    }
    

    The step order matters in Rust. count is a copied number, so nothing still borrows votes or name when insert runs. With the *, count is a plain i32 and the map is no longer borrowed once the line ends. Without it, count would be a &i32, a reference into the map, which only works here because it is last used inside the insert call; copying the number out keeps the code simple. Reading the map through get never adds a key; only the insert does.

    Following two calls

    For Ana with 3 votes, get finds the entry and count is 3, so insert stores 4 under "Ana", replacing the 3. For Cara, who isn't in the map, get gives None, the default makes count 0, and insert adds "Cara" with 1. The same two lines of code handle both people. This read, add one, write back pattern is the usual way to count things in a map.

    Edge cases and common mistakes

    • A new name. Indexing with votes[&name] would panic for a missing key. The get with a default avoids that.
    • Setting instead of adding. votes.insert(name, 1) would reset Ana's 3 votes to 1.
    • Using name after insert. The string has moved into the map. Using it again is the compile error "borrow of moved value".
    • An empty map. It works with no special case: the lookup finds None and the default gives 0.

    Testing

    The lesson's tests print the map as key: value lines sorted by key. Results from running the function:

    • {"Ana": 3, "Ben": 5}, "Ana" prints Ana: 4 and Ben: 5.
    • {"Ana": 3, "Ben": 5}, "Cara" prints Ana: 3, Ben: 5 and Cara: 1.
    • {}, "Max" prints Max: 1.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free