Start learning free

LESSON 137 OF 677 · DICTIONARIES - CHALLENGES

Count a Vote: Update a Map Count in Kotlin

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

    KOTLIN · DICTIONARIES - CHALLENGES

    Count A Vote in Kotlin, explained

    Problem overview

    The function countVote gets votes, a MutableMap<String, Int> from names to vote counts, and the name on a new vote. It counts the vote and returns the map. A person who already has votes gets one more. A name with no votes yet isn't in the map: it starts from 0, so after this vote it has 1. The map can be empty, and the order of entries doesn't matter.

    With {"Ana": 3, "Ben": 5} and "Ana", Ana goes to 4. With "Cara", who isn't in the map, she is added with 1. With an empty map and "Max", the map becomes {"Max": 1}.

    Approach

    Every case follows the same rule: new count = old count + 1, where the old count is 0 for a name that isn't there yet. So the only difficulty is reading a count that may be missing. Reading votes[name] gives null for a missing name, with the type Int?. getOrDefault(name, 0) gives a plain Int, either the stored count or 0, and one assignment then handles both cases.

    Step by step

    1. Read the old count. votes.getOrDefault(name, 0) in a val named count.
    2. Store the new count. votes[name] = count + 1. For a new name this adds the key; for an existing one it replaces the old count.
    3. Return votes. Only the count of name changed.

    The solution in Kotlin

    class Solution {
        fun countVote(votes: MutableMap<String, Int>, name: String): MutableMap<String, Int> {
            val count = votes.getOrDefault(name, 0)
            votes[name] = count + 1
            return votes
        }
    }
    

    Printing each result as sorted key: value lines (the tests' format) gives, for the three examples:

    Ana: 4
    Ben: 5
    
    Ana: 3
    Ben: 5
    Cara: 1
    
    Max: 1
    

    The read doesn't change the map. Only the assignment does, and that is the moment a new name gets added.

    Edge cases and common mistakes

    • Forcing the read. votes[name]!! + 1 compiles, but for a name with no votes votes[name] is null, and !! on it crashes the program with a NullPointerException.
    • Not handling the null. votes[name] + 1 doesn't compile: the compiler reports that the operator call is prohibited on a nullable receiver of type Int?.
    • Only updating existing names. Assigning only inside an if (name in votes) would lose the first vote of every new name.
    • Adding 1 twice. The default is 0 and the vote adds 1. A default of 1 would give a new name 2 votes.
    • Other entries. Ben's 5 stays 5 when Ana votes.

    Another way

    The Elvis operator gives the same result. votes[name] ?: 0 uses 0 when the read is null:

    val count = votes[name] ?: 0
    

    Either form is fine. The lesson's steps use getOrDefault, which says "this key, or this default" in one call.

    A third form, votes.merge(name, 1, Int::plus), does the whole update in one call: it stores 1 for a new name and adds 1 to an existing count. It gives the same maps as the lesson's solution on all three examples, but it hides the reading and the writing that this lesson wants you to see.

    Testing

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