Kotlin maps: counting and indexing
Count words with groupingBy and build a lookup map with getOrPut.
On this page
Kotlin maps and lambdas.
- Count words with groupingBy and build a lookup map with getOrPut.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
Kotlin has read-only Map and MutableMap types. mapOf and mutableMapOf keep the order of insertion when printed. groupingBy { key }.eachCount() counts how many elements share each key in one pass. getOrPut(key) { default } returns the existing value or creates and stores a new one, which is the clean way to build a map of lists.
The word-frequency map is sorted by count, highest first, with ties broken by the word, using compareBy with negative counts. The index map groups words by their first letter. Both run in O(n) apart from the sorting, because map lookups take O(1) on average.
Code example
fun main() {
val text = "the cat and the hat and the bat"
val freq = text.split(" ").groupingBy { it }.eachCount()
println(freq.entries.sortedWith(compareBy({ -it.value }, { it.key })).joinToString(" ") { "${it.key}=${it.value}" })
val index = mutableMapOf<Char, MutableList<String>>()
for (word in listOf("apple", "avocado", "banana", "blueberry", "cherry")) {
index.getOrPut(word[0]) { mutableListOf() }.add(word)
}
println(index)
println(index['b']?.size ?: 0)
println(index['z']?.size ?: 0)
}the=3 and=2 bat=1 cat=1 hat=1
{a=[apple, avocado], b=[banana, blueberry], c=[cherry]}
2
0Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
fun main() { val text = "the cat and the hat and the bat" val freq = text.split(" ").groupingBy { it }.eachCount() println(freq.entries.sortedWith(compareBy({ -it.value }, { it.key })).joinToString(" ") { "${it.key}=${it.value}" }) val index = mutableMapOf<Char, MutableList<String>>() for (word in listOf("apple", "avocado", "banana", "blueberry", "cherry")) { index.getOrPut(word[0]) { mutableListOf() }.add(word) } println(index) println(index['b']?.size ?: 0) println(index['z']?.size ?: 0)}Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Count each distinct word in a single pass. | — | — | |
| Highest counts first, ties alphabetical. | — | the=3 and=2 bat=1 cat=1 hat=1 | |
| Create the list for a letter the first time and then add to it. | — | the=3 and=2 bat=1 cat=1 hat=1 | |
| A mutable map prints its entries in insertion order. | — | the=3 and=2 bat=1 cat=1 hat=1
{a=[apple, avocado], b=[banana, blueberry], c=[cherry]} | |
| Two words start with b. | — | the=3 and=2 bat=1 cat=1 hat=1
{a=[apple, avocado], b=[banana, blueberry], c=[cherry]}
2 | |
| A missing key gives null, and ?: turns it into 0. | — | the=3 and=2 bat=1 cat=1 hat=1
{a=[apple, avocado], b=[banana, blueberry], c=[cherry]}
2
0 |
Behind the scenes
How Kotlin processes this code
Kotlin commonly compiles to JVM bytecode, which the JVM executes.
Cost and common mistakes
Counting and indexing are O(n); the sort is O(k log k) for k distinct words.
- map[key] returns null for a missing key. Use getValue if a missing key is a bug.
- A read-only Map is only a read-only view. If someone holds the mutable original, the contents can still change.
- Using a mutable key and changing it after insertion breaks lookups.
Try it yourself
How would you find the most frequent word?
Reveal answer and reasoning
freq.maxByOrNull { it.value }?.key; with ties, it returns the first one encountered.