- Tell read-only and mutable collections apart
- Create a
List, aSetand aMapand access their elements - Process collections with
forEach,map,filter,sortedand other functions
A playlist in a music app, a cart in an online shop, the contacts on your phone — everywhere there are groups of values. You cannot create a separate variable for every song. For this, Kotlin has collections: the list (List), the set (Set) and the map (Map). The lambdas you learned in the previous lesson will show their real power here.
List and MutableList
A list is an ordered group of elements, and the same element may appear more than once. You reach an element by its index, and counting starts from 0. Every Kotlin collection comes in two kinds: listOf(...) creates a read-only list, while mutableListOf(...) creates a list whose elements you can add, remove and change.
fun main() {
val fruits = listOf("apple", "pear", "grape")
println(fruits)
println(fruits[0])
println(fruits.size)
println("pear" in fruits)
val cart = mutableListOf("bread")
cart.add("milk")
cart.add("cheese")
cart.remove("bread")
cart[0] = "kefir"
println(cart)
}[apple, pear, grape] apple 3 true [kefir, cheese]
You can walk through a list with an ordinary for loop, but in Kotlin forEach is used very often. If you also need the element's position, forEachIndexed gives you both the index and the element:
fun main() {
val cities = listOf("Baku", "Ganja", "Shaki")
cities.forEach { println(it) }
cities.forEachIndexed { i, city -> println("${i + 1}. $city") }
}Baku Ganja Shaki 1. Baku 2. Ganja 3. Shaki
map, filter and other operations
The most powerful collection tools are functions that take lambdas. filter keeps the elements that match a condition, and map turns every element into another value. Neither of them changes the old list — they return a new list. There are also ready-made functions such as sum, average, max, sorted, take, count and any:
fun main() {
val scores = listOf(78, 92, 65, 88, 100)
println(scores.filter { it >= 80 })
println(scores.map { it / 10 })
println(scores.sum())
println(scores.average())
println(scores.max())
println(scores.sorted())
println(scores.sortedDescending().take(3))
println(scores.count { it < 70 })
println(scores.any { it == 100 })
}[92, 88, 100] [7, 9, 6, 8, 10] 423 84.6 100 [65, 78, 88, 92, 100] [100, 92, 88] 1 true
average() always returns a Double: 423 / 5 → 84.6.You can link these functions with dots into a chain — each step works on the result of the previous one. Below, the long words are selected first, then written in capital letters and finally sorted alphabetically:
fun main() {
val languages = listOf("kotlin", "java", "swift", "go", "python")
val result = languages
.filter { it.length > 4 }
.map { it.uppercase() }
.sorted()
println(result)
}[KOTLIN, PYTHON, SWIFT]
sorted() is one line, but an algorithm like this one works behind it. Watch how the elements change places step by step.Set: a group without duplicates
A set (Set) keeps every element only once: an element added again is simply ignored. This is handy, for example, for the cities you have travelled to or for counting unique visitors. You can intersect, unite and subtract sets just like in mathematics.
fun main() {
val visited = mutableSetOf("Baku", "Shaki", "Baku", "Quba")
println(visited)
visited.add("Shaki")
visited.add("Lankaran")
println(visited.size)
val a = setOf(1, 2, 3, 4)
val b = setOf(3, 4, 5)
println(a intersect b)
println(a union b)
println(a subtract b)
}[Baku, Shaki, Quba] 4 [3, 4] [1, 2, 3, 4, 5] [1, 2]
Map: keys and values
A map (Map) stores “key → value” pairs, like a dictionary: you look up a capital by the name of its country. Pairs are written with the word to: "Azerbaijan" to "Baku". You get a value with map[key]; if there is no such key, the result is null — and the Elvis operator from the null safety lesson comes in very handy. When printed, a map looks like {key=value}.
fun main() {
val capitals = mapOf("Azerbaijan" to "Baku", "Japan" to "Tokyo")
println(capitals["Azerbaijan"])
println(capitals["France"])
println(capitals["France"] ?: "unknown")
val stock = mutableMapOf("apple" to 10, "pear" to 4)
stock["apple"] = 7
stock["grape"] = 12
println(stock)
for ((fruit, count) in stock) {
println("$fruit: $count")
}
}Baku
null
unknown
{apple=7, pear=4, grape=12}
apple: 7
pear: 4
grape: 12A typical use of maps is counting things. Below, the votes of a class survey are counted: for every vote the current count is taken (0 if there is none yet) and increased by 1:
fun main() {
val votes = listOf("tea", "coffee", "tea", "juice", "tea", "coffee")
val counts = mutableMapOf<String, Int>()
for (v in votes) {
counts[v] = (counts[v] ?: 0) + 1
}
println(counts)
println(votes.groupingBy { it }.eachCount())
}{tea=3, coffee=2, juice=1}
{tea=3, coffee=2, juice=1}mutableMapOf<String, Int>().| Collection | Read-only | Mutable | When to choose it |
|---|---|---|---|
List | listOf(1, 2) | mutableListOf(1, 2) | order matters, duplicates allowed |
Set | setOf(1, 2) | mutableSetOf(1, 2) | each element only once |
Map | mapOf("a" to 1) | mutableMapOf("a" to 1) | lookup by key |
Key points
listOf,setOfandmapOfcreate read-only collections;mutableListOf,mutableSetOfandmutableMapOfcreate mutable ones.- List indexes start at 0; a printed list looks like
[1, 2, 3]. filterselects elements,maptransforms them andforEachdoes something with each one; results are new collections.- A
Setkeeps no duplicates and supports intersection, union and difference. - A
Mapstores key–value pairs; a missing key givesnull, and a printed map looks like{a=1, b=2}.
Check yourself
10 questions. Every correct answer earns XP.
add?