Beginner: Kotlin · Classes, objects and collections · topic 13 of 50 · 30 min
Collection operations
Explanation
Why operations instead of loops?
A loop says how to do something step by step. A collection operation says what you want: "the names of paid orders over Rs 500, sorted by amount". The code is shorter, reads like the requirement, and leaves fewer places for off-by-one mistakes. Every operation below returns a new collection or value; the original list is not changed.
data class Order(val id: Int, val customer: String, val amount: Int, val paid: Boolean, val city: String)
val orders = listOf(
Order(1, "Asha", 450, true, "Pune"),
Order(2, "Ravi", 1200, false, "Mumbai"),
Order(3, "Meena", 799, true, "Pune"),
Order(4, "Tom", 2300, true, "Mumbai"),
)Transform and filter
val paid = orders.filter { it.paid } // 3 orders
val names = orders.map { it.customer } // [Asha, Ravi, Meena, Tom]
val bigPaidNames = orders.filter { it.paid && it.amount > 500 }.map { it.customer }
println(bigPaidNames) // [Meena, Tom]Totals and counts
println(orders.sumOf { it.amount }) // 4749
println(orders.count { !it.paid }) // 1
println(orders.maxOf { it.amount }) // 2300
println(orders.maxByOrNull { it.amount }?.customer) // Tom
println(orders.map { it.amount }.average()) // 1187.25Sorting
val cheapFirst = orders.sortedBy { it.amount }.map { it.id } // [1, 3, 2, 4]
val richFirst = orders.sortedByDescending { it.amount }.map { it.id } // [4, 2, 3, 1]Finding and checking
val firstPune = orders.first { it.city == "Pune" } // Order 1
val inDelhi = orders.firstOrNull { it.city == "Delhi" } // null
println(orders.any { it.amount > 2000 }) // true
println(orders.all { it.amount > 100 }) // true
println(orders.none { it.city == "Goa" }) // trueGrouping and building maps
val byCity: Map<String, List<Order>> = orders.groupBy { it.city }
println(byCity.mapValues { (_, list) -> list.sumOf { it.amount } }) // {Pune=1249, Mumbai=3500}
val byId: Map<Int, Order> = orders.associateBy { it.id }
println(byId[3]?.customer) // Meena| Operation | Returns |
|---|---|
| map, filter, sortedBy, take(n), distinct() | A new List |
| sumOf, count, maxOf, average | A number |
| first, firstOrNull, find | One item (or null) |
| any, all, none | Boolean |
| groupBy, associateBy | A Map |
Read a chain from top to bottom, one step per line, as in the examples above. When the result is wrong, check each step separately: put the first two steps in a val, print it, then add the next step. This makes chains easy to debug.
Sequences for big data
Each step in a chain creates a new list. For a few thousand items that is fine. For very large collections, or when you only need the first few results, call asSequence() first: steps are then applied lazily, item by item, without building intermediate lists. Finish with toList() or another terminal operation.
val firstThreeBig = (1..1_000_000).asSequence()
.map { it * 2 }
.filter { it % 3 == 0 }
.take(3)
.toList() // [6, 12, 18]: only a few items are processedCommon mistakes
- Using first { } when there might be no match: it throws. Use firstOrNull.
- Calling sortedBy and expecting the original list to change. It returns a new list.
- Very long chains that are hard to read. Name intermediate results with val.
- Calling .size on the result of filter just to count: use count { } directly.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Collection operations · 1/7
Collection operations say what you want instead of how to loop. They return new collections and leave the original unchanged.
Prefer a video by a teacher? Find free videos on “kotlin collection functions map filter groupBy sortedBy” on YouTube ↗
In real life: A daily sales report
A clothing store chain gets every sale of the day as a list. The manager's app shows: total sales, sales per store sorted from highest, the best-selling item, and whether any refund is above Rs 5,000. Each figure is one short chain of collection operations instead of nested loops.
data class Sale(val store: String, val item: String, val amount: Int)
fun main() {
val sales = listOf(Sale("Andheri", "Kurta", 899), Sale("Bandra", "Saree", 2499),
Sale("Andheri", "Kurta", 899), Sale("Bandra", "Dupatta", 399))
println("Total: ${sales.sumOf { it.amount }}")
sales.groupBy { it.store }
.mapValues { (_, s) -> s.sumOf { it.amount } }
.entries.sortedByDescending { it.value }
.forEach { println("${it.key}: ${it.value}") }
println(sales.groupingBy { it.item }.eachCount().maxByOrNull { it.value }?.key) // Kurta
}Practice (0/3 done)
What does this print? val nums = listOf(5, 12, 7, 20, 3) println(nums.filter { it > 6 }.map { it / 2 })
What does listOf("ant", "bee", "cat").firstOrNull { it.startsWith("d") } return?
Given a list of data class Student(name, city, marks), write one chain for each: (1) names of students with 75+ sorted by marks descending, (2) average marks per city, (3) the topper's name, (4) whether anyone failed (below 33), (5) a Map from name to Student.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Inheritance and interfacesClasses, objects and collections · same module
- Data, enum and sealed classes, and objectsClasses, objects and collections · same module
- Array methods: map, filter, reduce and friendsJavaScript Programming (language in depth) · Arrays and objects
- Streams: filter, map and collectJava Programming (Core to Spring Boot) · Lambdas, streams and files
- Arrays and array methodsFrontend Web Development · JavaScript basics
- LINQ basics: query data in a few linesC# and .NET · Collections, generics and LINQ
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Does orders.sortedBy { it.amount } change orders?
Answer: No, it returns a new sorted list
Most collection operations return new collections.
Which operation turns List<Order> into Map<String, List<Order>>?
Answer: groupBy
groupBy collects items under each key.
What does listOf(2, 4, 6).all { it % 2 == 0 } return?
Answer: true
Every item is even.
When is asSequence() helpful?
Answer: For very large collections or when only a few results are needed
Sequences avoid building intermediate lists.
What does find return when nothing matches?Related
Answer: undefined
find returns undefined; findIndex returns -1.
Stream.of(1, 2, 3).map(n -> n * 10).filter(n -> n > 10).toList() is…Related
What does find return when nothing matches?Related
Answer: undefined
find gives undefined when no item passes the test (indexOf is the one that gives -1).
Which LINQ method transforms each item into something else?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Classes, objects and collections”. The module exam comes next.
- Module 3 exam: Classes, objects and collections · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Coroutines and Flow. 50 topics left in the course before the final exam.