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
- Read the old count.
votes.getOrDefault(name, 0)in avalnamedcount. - 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. - Return
votes. Only the count ofnamechanged.
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]!! + 1compiles, but for a name with no votesvotes[name]isnull, and!!on it crashes the program with aNullPointerException. - Not handling the null.
votes[name] + 1doesn't compile: the compiler reports that the operator call is prohibited on a nullable receiver of typeInt?. - 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.
