Chapter 17: Collections β Operations
Collections β Operations β this is the chapter where your Kotlin collections come to life and start doing real magic! βπ
In the last chapter, we learned how to create collections (read-only vs mutable, listOf, setOf, etc.). Now, weβll focus on operations β the functions that let you transform, filter, group, and aggregate data in clean, concise ways. These are the tools you’ll use every day in real Kotlin projects (Android apps, backend services, data processing).
We’ll go super slowly, like we’re sitting together in a quiet Bandra cafΓ© β I’ll explain each operation with real-life analogies, complete runnable examples, step-by-step breakdowns, tables, common mistakes with fixes, and fun facts so everything sticks perfectly.
All examples use Kotlin 1.9+ (2026 standard) β copy-paste them into IntelliJ and run!
Letβs dive in!
1. Transformation Operations β Filter, Map, FlatMap
These operations create new collections from existing ones β they are immutable (don’t change the original).
A. filter β Keep Only What Matches
filter takes a predicate (condition lambda) and returns a new collection with elements that match it.
Real-life analogy: You have a basket of fruits β filter is like picking only the apples, leaving the basket unchanged.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
fun main() { val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Filter even numbers val evenNumbers = numbers.filter { num -> num % 2 == 0 // Condition } println("Even numbers: $evenNumbers") // [2, 4, 6, 8, 10] // Shorter with it val bigNumbers = numbers.filter { it > 5 } // [6, 7, 8, 9, 10] // Filter on strings val cities = listOf("Mumbai", "Pune", "Delhi", "Bangalore", "Chennai") val longCities = cities.filter { city -> city.length > 5 } // [Mumbai, Bangalore, Chennai] } |
Step-by-step:
- For each element, apply the lambda β if true, keep it.
- Returns a new List (same type as original if possible).
B. map β Transform Each Element
map takes a transformation lambda and returns a new collection with transformed elements.
Real-life analogy: You have a list of apples β map is like turning each apple into apple juice.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
fun main() { val numbers = listOf(1, 2, 3, 4, 5) // Map to squares val squares = numbers.map { num -> num * num } println("Squares: $squares") // [1, 4, 9, 16, 25] // Map strings val cities = listOf("mumbai", "pune", "delhi") val upperCities = cities.map { it.uppercase() } // [MUMBAI, PUNE, DELHI] // Complex map val users = listOf("Amit:22", "Priya:24") val ages = users.map { user -> user.split(":")[1].toInt() } // [22, 24] } |
C. flatMap β Map + Flatten Nested Collections
flatMap is like map, but if your transformation returns a collection, it flattens them into one big collection.
Real-life analogy: You have boxes of fruits (map opens each box into a list) β flatMap pours all fruits into one big basket.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
fun main() { val orders = listOf( listOf("Laptop", "Mouse"), listOf("Phone", "Charger"), listOf("Book") ) // Map (nested lists) val mapped = orders.map { order -> order.map { it.uppercase() } } println(mapped) // [[LAPTOP, MOUSE], [PHONE, CHARGER], [BOOK]] // flatMap (flattened) val flatMapped = orders.flatMap { order -> order.map { it.uppercase() } } println(flatMapped) // [LAPTOP, MOUSE, PHONE, CHARGER, BOOK] // Common use: Split strings val sentences = listOf("Hello Webliance", "Kotlin is fun") val words = sentences.flatMap { it.split(" ") } // [Hello, Webliance, Kotlin, is, fun] } |
2. Association & Grouping Operations β associate, groupBy
These create maps from collections.
A. associate β Create Map from Key-Value Pairs
associate takes a lambda that returns a Pair (key to value) β builds a Map.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
fun main() { val names = listOf("Amit", "Priya", "Rahul") // Associate with length val nameLengths = names.associate { name -> name to name.length } println(nameLengths) // {Amit=4, Priya=5, Rahul=5} // associateBy β key only val nameStarts = names.associateBy { it.first() } println(nameStarts) // {A=Amit, P=Priya, R=Rahul} // Last value wins duplicates // associateWith β value only val nameCaps = names.associateWith { it.uppercase() } println(nameCaps) // {Amit=AMIT, Priya=PRIYA, Rahul=RAHUL} } |
B. groupBy β Group Elements into Map<List>
groupBy takes a key selector lambda β returns Map<Key, List<T>>
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fun main() { val students = listOf( "Amit:25", "Priya:24", "Rahul:25", "Sneha:23", "Vikram:24" ) // Group by age val groupedByAge = students.groupBy { student -> student.split(":")[1].toInt() // age as key } println(groupedByAge) // {25=[Amit:25, Rahul:25], 24=[Priya:24, Vikram:24], 23=[Sneha:23]} // Group by first letter val groupedByInitial = students.groupBy { it[0] } // 'A', 'P', etc. println(groupedByInitial) } |
3. Pairing & Splitting β zip, partition, chunked, windowed
A. zip β Pair Elements from Two Collections
zip combines two collections into List<Pair> or transforms with lambda.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fun main() { val names = listOf("Amit", "Priya", "Rahul") val ages = listOf(22, 24, 25) // Simple zip val pairs = names.zip(ages) println(pairs) // [(Amit, 22), (Priya, 24), (Rahul, 25)] // Zip with transformation val messages = names.zip(ages) { name, age -> "$name is $age years old" } println(messages) // [Amit is 22 years old, Priya is 24 years old, Rahul is 25 years old] } |
B. partition β Split into Two Lists Based on Condition
partition returns Pair<List<T>, List<T>> β matching and non-matching.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
fun main() { val numbers = listOf(1, -2, 3, -4, 5) val (positive, negative) = numbers.partition { it > 0 } println("Positive: $positive") // [1, 3, 5] println("Negative: $negative") // [-2, -4] } |
C. chunked β Split into Chunks of Size N
chunked returns List<List<T>> of chunks.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
fun main() { val items = listOf(1,2,3,4,5,6,7,8,9,10) val groups = items.chunked(3) println(groups) // [[1,2,3], [4,5,6], [7,8,9], [10]] // With transformation val sums = items.chunked(3) { it.sum() } println(sums) // [6, 15, 24, 10] } |
D. windowed β Sliding Windows of Size N
windowed returns List<List<T>> of overlapping windows.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fun main() { val numbers = listOf(1,2,3,4,5,6) val windows = numbers.windowed(3, step = 1) println(windows) // [[1,2,3], [2,3,4], [3,4,5], [4,5,6]] // Partial windows val partial = numbers.windowed(3, step = 2, partialWindows = true) println(partial) // [[1,2,3], [3,4,5], [5,6]] // With transformation val averages = numbers.windowed(3) { it.average() } println(averages) // [2.0, 3.0, 4.0, 5.0] } |
4. Folding & Reducing β fold, reduce, sumOf, etc.
These aggregate collections into a single value.
A. fold β Aggregate with Initial Value
fold takes an initial accumulator + lambda β applies to each element.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fun main() { val numbers = listOf(1,2,3,4,5) val sum = numbers.fold(0) { acc, num -> acc + num } // 0+1+2+3+4+5 = 15 val product = numbers.fold(1) { acc, num -> acc * num } // 1*1*2*3*4*5 = 120 // Fun example β build string val sentence = numbers.fold("Numbers:") { acc, num -> "$acc $num" } println(sentence) // Numbers: 1 2 3 4 5 } |
B. reduce β Aggregate Without Initial Value
reduce is like fold but uses first element as initial accumulator.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
val numbers = listOf(1,2,3,4,5) val product = numbers.reduce { acc, num -> acc * num } // 1*2*3*4*5 = 120 // Error if empty list // numbers.reduce { ... } // IllegalArgumentException if empty! |
C. sumOf β Sum with Projection
sumOf sums a projection (transformed values).
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
val people = listOf("Amit", "Priya", "Rahul") val totalLength = people.sumOf { it.length } // 4 + 5 + 5 = 14 val numbers = listOf(1,2,3,4,5) val sumEven = numbers.sumOf { if (it % 2 == 0) it else 0 } // 2+4 = 6 |
Other aggregates: count(), maxOf { }, minOf { }, average()
5. Sequences (asSequence()) β Lazy Collections
Sequences are like collections but lazy β they compute only when needed.
Use asSequence() to convert a collection to a sequence.
Why use sequences?
- For large data β avoid creating intermediate collections
- Better performance for chained operations
- Infinite sequences possible
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fun main() { val numbers = listOf(1,2,3,4,5,6,7,8,9,10) // Eager (collection) β creates intermediate lists val eager = numbers.filter { println("Filter $it"); it % 2 == 0 }.map { println("Map $it"); it * 2 }.first() println("---") // Lazy (sequence) β computes only what's needed val lazy = numbers.asSequence().filter { println("Filter $it"); it % 2 == 0 }.map { println("Map $it"); it * 2 }.first() } |
Output:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Filter 1 Filter 2 Filter 3 Filter 4 Filter 5 Filter 6 Filter 7 Filter 8 Filter 9 Filter 10 Map 2 Map 4 Map 6 Map 8 Map 10 --- Filter 1 Filter 2 Map 2 |
See? Lazy version only processed until it found the first even number!
Infinite sequence example:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
val infinite = generateSequence(1) { it + 1 } // 1,2,3,... .asSequence() .filter { it % 3 == 0 } .take(5) // Take first 5 multiples of 3 println(infinite.toList()) // [3,6,9,12,15] |
Quick Recap Table (Your Cheat Sheet)
| Operation | Purpose | Returns | Example |
|---|---|---|---|
| filter | Keep matching elements | New collection | .filter { it > 0 } |
| map | Transform each | New collection | .map { it * 2 } |
| flatMap | Transform + flatten | New flattened collection | .flatMap { it.split(” “) } |
| associate | Build Map from pairs | Map | .associate { it to it.length } |
| groupBy | Group into Map<List> | Map<Key, List<T>> | .groupBy { it % 2 } |
| zip | Pair with another collection | List<Pair> or transformed | .zip(other) { a, b -> a + b } |
| partition | Split into two lists | Pair<List<T>, List<T>> | .partition { it > 0 } |
| chunked | Split into chunks | List<List<T>> | .chunked(3) |
| windowed | Sliding windows | List<List<T>> | .windowed(3) |
| fold | Aggregate with initial | Single value | .fold(0) { acc, num -> acc + num } |
| reduce | Aggregate without initial | Single value | .reduce { acc, num -> acc + num } |
| sumOf | Sum of projections | Long/Double | .sumOf { it.length } |
| asSequence | Convert to lazy sequence | Sequence | .asSequence().filter{…}.map{…}.toList() |
Common Newbie Mistakes & Fixes
| Mistake | Problem | Fix |
|---|---|---|
| Using map instead of flatMap | Nested lists instead of flat | Use flatMap when transform returns collection |
| Forgetting toList() after operations | Stream/Sequence β no output | Chain .toList() or use terminal like .forEach |
| Using reduce on empty collection | IllegalArgumentException | Check empty or use fold with initial |
| Not using asSequence on large data | OutOfMemoryError or slow | Add .asSequence() for lazy processing |
| Confusing chunked and windowed | Wrong splitting | chunked = non-overlap, windowed = sliding |
Homework for You (Letβs Make It Fun!)
- Basic From listOf(1,2,3,4,5,6,7,8,9,10) β filter odds β map to squares β print list.
- Medium From list of strings [“apple:5”, “banana:3”, “cherry:8”] β use associate to make Map<String, Int> (fruit to quantity).
- Advanced From list of numbers 1 to 20 β use partition to split even/odd β print sums using sumOf.
- Fun From list of sentences β use flatMap to get all words β groupBy first letter.
- Challenge Create an infinite sequence of Fibonacci numbers β use take(10) β print using fold to build a string.
Youβve just mastered Kotlinβs collection operations β now you can process data like a pro!
Ready for Chapter 18: Sequences & Lazy Evaluation? Or want me to explain any operation again with more examples or debug your code? Just tell me β Iβm right here with another cup of cutting chai! βπ<|control12|>Hey Webliance! Welcome to Chapter 17: Collections β Operations β this is the chapter where your Kotlin collections come to life and start doing real magic! βπ
In the last chapter, we learned how to create collections (read-only vs mutable, listOf, setOf, etc.). Now, weβll focus on operations β the functions that let you transform, filter, group, and aggregate data in clean, concise ways. These are the tools you’ll use every day in real Kotlin projects (Android apps, backend services, data processing).
We’ll go super slowly, like we’re sitting together in a quiet Bandra cafΓ© β I’ll explain each operation with real-life analogies, complete runnable examples, step-by-step breakdowns, tables, common mistakes with fixes, and fun facts so everything sticks perfectly.
All examples use Kotlin 1.9+ (2026 standard) β copy-paste them into IntelliJ and run!
Letβs dive in!
1. Transformation Operations β Filter, Map, FlatMap
These operations create new collections from existing ones β they are immutable (don’t change the original).
A. filter β Keep Only What Matches
filter takes a predicate (condition lambda) and returns a new collection with elements that match it.
Real-life analogy: You have a basket of fruits β filter is like picking only the apples, leaving the basket unchanged.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
fun main() { val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Filter even numbers val evenNumbers = numbers.filter { num -> num % 2 == 0 // Condition } println("Even numbers: $evenNumbers") // [2, 4, 6, 8, 10] // Shorter with it val bigNumbers = numbers.filter { it > 5 } // [6, 7, 8, 9, 10] // Filter on strings val cities = listOf("Mumbai", "Pune", "Delhi", "Bangalore", "Chennai") val longCities = cities.filter { city -> city.length > 5 } // [Mumbai, Bangalore, Chennai] } |
Step-by-step:
- For each element, apply the lambda β if true, keep it.
- Returns a new List (same type as original if possible).
Fun fact: filter is lazy β it doesn’t create the new list until you use it (e.g., print or collect). This is why it’s efficient!
B. map β Transform Each Element
map takes a transformation lambda and returns a new collection with transformed elements.
Real-life analogy: You have a list of apples β map is like turning each apple into apple juice.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
fun main() { val numbers = listOf(1, 2, 3, 4, 5) // Map to squares val squares = numbers.map { num -> num * num } println("Squares: $squares") // [1, 4, 9, 16, 25] // Map strings val cities = listOf("mumbai", "pune", "delhi") val upperCities = cities.map { it.uppercase() } // [MUMBAI, PUNE, DELHI] // Complex map val users = listOf("Amit:22", "Priya:24") val ages = users.map { user -> user.split(":")[1].toInt() } // [22, 24] } |
Step-by-step:
- For each element, apply the lambda β get new value.
- Collects all new values into a new List.
Common mistake: Forgetting that map returns a new collection β original remains unchanged.
C. flatMap β Map + Flatten Nested Collections
flatMap is like map, but if your transformation returns a collection, it flattens them into one big collection.
Real-life analogy: You have boxes of fruits (map opens each box into a list) β flatMap pours all fruits into one big basket.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
fun main() { val orders = listOf( listOf("Laptop", "Mouse"), listOf("Phone", "Charger"), listOf("Book") ) // Map (nested lists) val mapped = orders.map { order -> order.map { it.uppercase() } } println(mapped) // [[LAPTOP, MOUSE], [PHONE, CHARGER], [BOOK]] // flatMap (flattened) val flatMapped = orders.flatMap { order -> order.map { it.uppercase() } } println(flatMapped) // [LAPTOP, MOUSE, PHONE, CHARGER, BOOK] // Common use: Split strings val sentences = listOf("Hello Webliance", "Kotlin is fun") val words = sentences.flatMap { it.split(" ") } // [Hello, Webliance, Kotlin, is, fun] } |
Step-by-step:
- For each element, apply lambda β get a collection.
- Flatten all into one big collection.
Fun fact: flatMap is perfect for processing JSON-like nested data.
2. Association & Grouping Operations β associate, groupBy
These create maps from collections.
A. associate β Create Map from Key-Value Pairs
associate takes a lambda that returns a Pair (key to value) β builds a Map.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
fun main() { val names = listOf("Amit", "Priya", "Rahul") // Associate with length val nameLengths = names.associate { name -> name to name.length } println(nameLengths) // {Amit=4, Priya=5, Rahul=5} // associateBy β key only val nameStarts = names.associateBy { it.first() } println(nameStarts) // {A=Amit, P=Priya, R=Rahul} // Last value wins duplicates // associateWith β value only val nameCaps = names.associateWith { it.uppercase() } println(nameCaps) // {Amit=AMIT, Priya=PRIYA, Rahul=RAHUL} } |
Step-by-step:
- Lambda returns Pair (key to value).
- If duplicate keys β last one wins.
B. groupBy β Group Elements into Map<List>
groupBy takes a key selector lambda β returns Map<Key, List<T>>
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fun main() { val students = listOf( "Amit:25", "Priya:24", "Rahul:25", "Sneha:23", "Vikram:24" ) // Group by age val groupedByAge = students.groupBy { student -> student.split(":")[1].toInt() // age as key } println(groupedByAge) // {25=[Amit:25, Rahul:25], 24=[Priya:24, Vikram:24], 23=[Sneha:23]} // Group by first letter val groupedByInitial = students.groupBy { it[0] } // 'A', 'P', etc. println(groupedByInitial) } |
Step-by-step:
- Lambda returns key for each element.
- Elements with same key go into the same List.
3. Pairing & Splitting Operations β zip, partition, chunked, windowed
A. zip β Pair Elements from Two Collections
zip combines two collections into List<Pair> or transforms with lambda.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fun main() { val names = listOf("Amit", "Priya", "Rahul") val ages = listOf(22, 24, 25) // Simple zip val pairs = names.zip(ages) println(pairs) // [(Amit, 22), (Priya, 24), (Rahul, 25)] // Zip with transformation val messages = names.zip(ages) { name, age -> "$name is $age years old" } println(messages) // [Amit is 22 years old, Priya is 24 years old, Rahul is 25 years old] } |
Step-by-step:
- Pairs corresponding elements (shorter list determines size).
- If lambda β apply to each pair.
B. partition β Split into Two Lists Based on Condition
partition returns Pair<List<T>, List<T>> β matching and non-matching.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
fun main() { val numbers = listOf(1, -2, 3, -4, 5) val (positive, negative) = numbers.partition { it > 0 } println("Positive: $positive") // [1, 3, 5] println("Negative: $negative") // [-2, -4] } |
Step-by-step:
- Lambda decides which list each element goes to.
- Use destructuring to get the pair.
C. chunked β Split into Chunks of Size N
chunked returns List<List<T>> of chunks.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
fun main() { val items = listOf(1,2,3,4,5,6,7,8,9,10) val groups = items.chunked(3) println(groups) // [[1,2,3], [4,5,6], [7,8,9], [10]] // With transformation val sums = items.chunked(3) { it.sum() } println(sums) // [6, 15, 24, 10] } |
Step-by-step:
- Splits into non-overlapping chunks of size N.
- Last chunk may be smaller.
D. windowed β Sliding Windows of Size N
windowed returns List<List<T>> of overlapping windows.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fun main() { val numbers = listOf(1,2,3,4,5,6) val windows = numbers.windowed(3, step = 1) println(windows) // [[1,2,3], [2,3,4], [3,4,5], [4,5,6]] // Partial windows val partial = numbers.windowed(3, step = 2, partialWindows = true) println(partial) // [[1,2,3], [3,4,5], [5,6]] // With transformation val averages = numbers.windowed(3) { it.average() } println(averages) // [2.0, 3.0, 4.0, 5.0] } |
Step-by-step:
- Creates sliding windows of size N, step S.
- partialWindows = true β includes smaller end windows.
4. Folding & Reducing Operations β fold, reduce, sumOf, etc.
These aggregate collections into a single value.
A. fold β Aggregate with Initial Value
fold takes an initial accumulator + lambda β applies to each element.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fun main() { val numbers = listOf(1,2,3,4,5) val sum = numbers.fold(0) { acc, num -> acc + num } // 0+1+2+3+4+5 = 15 val product = numbers.fold(1) { acc, num -> acc * num } // 1*1*2*3*4*5 = 120 // Fun example β build string val sentence = numbers.fold("Numbers:") { acc, num -> "$acc $num" } println(sentence) // Numbers: 1 2 3 4 5 } |
Step-by-step:
- Start with initial value.
- For each element: acc = lambda(acc, element)
B. reduce β Aggregate Without Initial Value
reduce is like fold but uses first element as initial accumulator.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
val numbers = listOf(1,2,3,4,5) val product = numbers.reduce { acc, num -> acc * num } // 1*2*3*4*5 = 120 // Error if empty list // numbers.reduce { ... } // IllegalArgumentException if empty! |
Step-by-step:
- Initial acc = first element
- Then apply lambda to rest
C. sumOf β Sum with Projection
sumOf sums a projection (transformed values).
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
val people = listOf("Amit", "Priya", "Rahul") val totalLength = people.sumOf { it.length } // 4 + 5 + 5 = 14 val numbers = listOf(1,2,3,4,5) val sumEven = numbers.sumOf { if (it % 2 == 0) it else 0 } // 2+4 = 6 |
Other aggregates:
- count() β total elements
- maxOf { } / minOf { } β max/min by projection
- average() β average (Double)
5. Sequences (asSequence()) β Lazy Processing for Efficiency
Sequences are like collections but lazy β they compute on-demand, avoiding intermediate collections.
Convert with .asSequence()
Real-life analogy: Collections = baking all cookies at once (eager). Sequences = baking one cookie when someone asks (lazy) β saves time if they only eat a few.
Example β Eager vs Lazy
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fun main() { val numbers = listOf(1,2,3,4,5,6,7,8,9,10) // Eager (collection) β executes everything val eager = numbers.filter { println("Filter $it"); it % 2 == 0 } .map { println("Map $it"); it * 2 } .first() println("---") // Lazy (sequence) β executes only what's needed val lazy = numbers.asSequence() .filter { println("Filter $it"); it % 2 == 0 } .map { println("Map $it"); it * 2 } .first() } |
Output:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Filter 1 Filter 2 Filter 3 Filter 4 Filter 5 Filter 6 Filter 7 Filter 8 Filter 9 Filter 10 Map 2 Map 4 Map 6 Map 8 Map 10 --- Filter 1 Filter 2 Map 2 |
Step-by-step: Lazy version stops after finding first even number (2) β much more efficient for large data!
Infinite sequence:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
val infinite = generateSequence(0) { it + 1 } // 0,1,2,3,... .asSequence() .filter { it % 3 == 0 } .take(5) // Take first 5 multiples of 3 println(infinite.toList()) // [0,3,6,9,12] |
When to use sequences?
- Large collections (>10k elements)
- Chained operations (filter + map + etc.)
- Infinite data (generators, sequences)
Quick Recap Table (Your Cheat Sheet)
| Operation | Purpose | Returns | Example |
|---|---|---|---|
| filter | Keep matching elements | New collection | .filter { it > 0 } |
| map | Transform each | New collection | .map { it * 2 } |
| flatMap | Transform + flatten | New flattened collection | .flatMap { it.split(” “) } |
| associate | Build Map from pairs | Map | .associate { it to it.length } |
| groupBy | Group into Map<List> | Map<Key, List<T>> | .groupBy { it % 2 } |
| zip | Pair with another collection | List<Pair> or transformed | .zip(other) { a, b -> a + b } |
| partition | Split into two lists | Pair<List<T>, List<T>> | .partition { it > 0 } |
| chunked | Split into chunks | List<List<T>> | .chunked(3) |
| windowed | Sliding windows | List<List<T>> | .windowed(3) |
| fold | Aggregate with initial | Single value | .fold(0) { acc, num -> acc + num } |
| reduce | Aggregate without initial | Single value | .reduce { acc, num -> acc + num } |
| sumOf | Sum of projections | Long/Double | .sumOf { it.length } |
| asSequence | Convert to lazy sequence | Sequence | .asSequence().filter{…}.map{…}.toList() |
Common Newbie Mistakes & Fixes
| Mistake | Problem | Fix |
|---|---|---|
| Using map instead of flatMap | Nested lists instead of flat | Use flatMap when transform returns collection |
| Forgetting toList() after operations | Stream/Sequence β no output | Chain .toList() or use terminal like .forEach |
| Using reduce on empty collection | IllegalArgumentException | Check empty or use fold with initial |
| Not using asSequence on large data | OutOfMemoryError or slow | Add .asSequence() for lazy processing |
| Confusing chunked and windowed | Wrong splitting | chunked = non-overlap, windowed = sliding |
Homework for You (Letβs Make It Fun!)
- Basic From listOf(1,2,3,4,5,6,7,8,9,10) β filter odds β map to squares β print list.
- Medium From list of strings [“apple:5”, “banana:3”, “cherry:8”] β use associate to make Map<String, Int> (fruit to quantity).
- Advanced From list of numbers 1 to 20 β use partition to split even/odd β print sums using sumOf.
- Fun From list of sentences β use flatMap to get all words β groupBy first letter.
- Challenge Create an infinite sequence of Fibonacci numbers β use take(10) β print using fold to build a string.
Youβve just mastered Kotlinβs collection operations β now you can process data like a pro!
