skip to Main Content

Kotlin Idiomatic Collections — The Ultimate Guide

January 21, 20266 minute read

  

Kotlin Idiomatic Collections — The Ultimate Guide

HR: how much experience do you have in Kotlin? 🤔

Le Candidate: 3 Yrs 😒

Both are happy, it seems. Do you really feel, you are using enough Kotlin having 3/4/5 yrs experience in Android Development? Or maybe just 30–35% of it.

Once, I tried to dig more about Kotlin Concepts, I realized, I’m a Pseudo Kotlin Dev, it has so many powerful methods/extension function and lot many things I never encountered with.

While solving DSA Question, just seeing an array, first thing comes into the mind that let’s write a for { } Loop 😂. If you’re solving the problem in Kotlin, there’s many alternatives. In this article, We’ll be going through all the Kotlin Idiomatic which is going to turn the table for us.

Kotlin’s standard library provides a rich set of collection operations that allow you to write concise, readable, safe, and efficient code. Using idiomatic Kotlin helps you avoid boilerplate loops, manual maps, and counters.

Transforming Collections: map, mapIndexed, flatMap, flatMapIndexed

Purpose: Transform each element of a collection.

val names = listOf("Alice", "Bob")
val upper = names.map { it.uppercase() } // [ALICE, BOB]val indexed = names.mapIndexed { i, n -> "$i:$n" } // [0:Alice, 1:Bob]
val nested = listOf(listOf(1,2), listOf(3,4))
val flatDoubled = nested.flatMap { it.map { it * 2 } } // [2,4,6,8]
| Function                     | Time Complexity | Notes / DSA Tips                                                                              |
| ---------------------------- | --------------- | --------------------------------------------------------------------------------------------- |
| `map` / `mapIndexed` | O(n) | Good for transforming arrays/lists of size n. Avoid inside nested loops if n is large. |
| `flatMap` / `flatMapIndexed` | O(n + m) | Flattens nested lists; m = total size of inner lists. Useful when flattening adjacency lists. |

Real-world: Transform database entities, flatten nested order items, apply discounts to product prices.

Filtering Collections: filter, take, drop, takeWhile, dropWhile

val nums = listOf(1,2,3,4,5)
val evens = nums.filter { it % 2 == 0 } // [2,4]val firstThree = nums.take(3) // [1,2,3]val restAfterTwo = nums.drop(2) // [3,4,5]

Real-world: Select active users, paginate lists, filter events, skip processed orders.

| Function                  | Time Complexity | Notes                                   |
| ------------------------- | --------------- | --------------------------------------- |
| `filter` | O(n) | Linear scan. Avoid inside nested loops. |
| `take(k)` / `drop(k)` | O(k) / O(n-k) | Efficient for slicing. |
| `takeWhile` / `dropWhile` | O(k) worst-case | Stops once condition fails. |

Searching & Boolean Checks: firstOrNull, lastOrNull, find, any, all, none

val words = listOf("apple", "banana", "cherry")
val firstB = words.firstOrNull { it.startsWith('b') } // banana
println(words.any { it.length > 5 }) // true
println(words.all { it.length > 0 }) // true

Real-world: Find a user by ID, check if any transaction failed, validate inputs.

| Function               | Time Complexity | Notes                                 |
| ---------------------- | --------------- | ------------------------------------- |
| `firstOrNull` / `find` | O(n) | Linear scan until match. |
| `lastOrNull` | O(n) | Linear from start. |
| `any` / `all` / `none` | O(n) worst-case | Stops early if condition met/not met. |

Removing Duplicates: distinct

val numbers = listOf(1,2,2,3)
val unique = numbers.distinct() // [1,2,3]

Real-world: Unique tags, email addresses, product IDs.

| Function     | Time Complexity | Notes                    |
| ------------ | --------------- | ------------------------ |
| `distinct()` | O(n) | Internally uses HashSet. |
| `distinctBy` | O(n) | Similar, based on key. |

Grouping & Partitioning: groupBy, partition, groupingBy

val names = listOf("Alice", "Bob", "Anna")
val grouped = names.groupBy { it.first() }
// {A=[Alice, Anna], B=[Bob]}

val (even, odd) = listOf(1,2,3,4).partition { it % 2 == 0 }
// even=[2,4], odd=[1,3]val letters = listOf('a','b','a')
val counts = letters.groupingBy { it }.eachCount() // {a=2, b=1}

Real-world: Categorize products, divide tasks, count frequencies, group users by role.

| Function                 | Time Complexity | Notes                          |
| ------------------------ | --------------- | ------------------------------ |
| `groupBy` | O(n) | Linear, creates Map of lists. |
| `partition` | O(n) | Linear, splits into two lists. |
| `groupingBy.eachCount()` | O(n) | Count frequencies efficiently. |

Sorting Collections: sorted, sortedBy, sortedWith, sortWith

data class User(val name: String, val salary: Int)
val users = mutableListOf(User("John",5000), User("Alice",7000))

val sortedUsers = users.sortedWith(compareByDescending<User> { it.salary }.thenBy { it.name })
println(sortedUsers) // New sorted list
users.sortWith(compareByDescending<User> { it.salary }.thenBy { it.name })
println(users) // Original list sorted in-place

Real-world: Leaderboards, payroll, priority queues.

| Function                           | Time Complexity | Notes                          |
| ---------------------------------- | --------------- | ------------------------------ |
| `sorted`, `sortedBy`, `sortedWith` | O(n log n) | Returns new list. Stable sort. |
| `sortWith` | O(n log n) | In-place, stable. |

Aggregation & Reduction: fold, reduce, sumOf

val nums = listOf(1,2,3)
val sum = nums.fold(0) { acc, n -> acc + n } // 6
val product = nums.reduce { acc, n -> acc * n } // 6
val totalSalary = users.sumOf { it.salary } // 12000

Real-world: Total revenue, inventory valuation, product of metrics.

| Function          | Time Complexity | Notes                           |
| ----------------- | --------------- | ------------------------------- |
| `fold` / `reduce` | O(n) | Linear traversal, accumulation. |
| `sumOf` | O(n) | Linear sum of values. |

Mapping to Keys & Values: associateBy, associateWith, zip

val mapByName = users.associateBy { it.name } 
// {"John"=User("John",5000), "Alice"=User("Alice",7000)}

val scores = listOf(90, 80)
val zipped = listOf("Alice", "Bob").zip(scores) { name, score -> "$name scored $score" }
// ["Alice scored 90", "Bob scored 80"]

Real-world: Lookup maps, report generation, pairing names with values.

| Function                        | Time Complexity | Notes                        |
| ------------------------------- | --------------- | ---------------------------- |
| `associateBy` / `associateWith` | O(n) | Creates a HashMap; linear. |
| `zip` | O(n) | Linear pairwise combination. |

Flattening Collections: flatten, flatMap

val nested = listOf(listOf(1,2), listOf(3,4))
val flat = nested.flatten() // [1,2,3,4]val flatDoubled = nested.flatMap { it.map { it*2 } } // [2,4,6,8]

Real-world: Flatten orders, transform items in batch operations.

| Function    | Time Complexity | Notes                       |
| ----------- | --------------- | --------------------------- |
| `flatten()` | O(n) | n = total elements |
| `flatMap()` | O(n + m) | Linear with transformation. |

Lazy Evaluation: asSequence

val numbers = (1..1_000_000).asSequence()
val result = numbers.map { it * 2 }
.filter { it % 3 == 0 }
.take(5)
.toList()
println(result)

Real-world: Process huge datasets efficiently, stream logs, large computations.

| Function     | Time Complexity | Notes                                                        |
| ------------ | --------------- | ------------------------------------------------------------ |
| `asSequence` | O(1) creation | Evaluation is lazy; terminal operation triggers actual work. |

Sliding Windows / Batching: windowed, chunked

val numbers = (1..5).toList()
println(numbers.windowed(3)) // [[1,2,3],[2,3,4],[3,4,5]]println(numbers.chunked(2)) // [[1,2],[3,4],[5]]

Real-world: Analytics, rolling averages, batch processing.

| Function      | Time Complexity | Notes                                   |
| ------------- | --------------- | --------------------------------------- |
| `windowed(k)` | O(n*k) | Each window copied, beware for large k. |
| `chunked(k)` | O(n) | Linear, slices into batches. |

Index-aware Iteration: withIndex, mapIndexed

val names = listOf("Alice", "Bob")
for ((index, name) in names.withIndex()) {
println("$index -> $name")
}

Real-world: Assign positions, show rankings, row numbers.

| Function     | Time Complexity | Notes                         |
| ------------ | --------------- | ----------------------------- |
| `withIndex` | O(n) | Linear; no extra overhead |
| `mapIndexed` | O(n) | Transform elements with index |

Side-effects in Chains: onEach

val doubled = (1..5).map { it*2 }
.onEach { println(it) }
.toList()

Real-world: Logging, debugging, triggering events while chaining.

| Function | Time Complexity | Notes                               |
| -------- | --------------- | ----------------------------------- |
| `onEach` | O(n) | Linear, performs action per element |

Conditional Returns: takeIf / takeUnless

val number = 10
println(number.takeIf { it % 2 == 0 }) // 10
println(number.takeUnless { it % 2 == 0 }) // null

Real-world: Inline validation, optional filtering, pipeline-friendly.

| Function                | Time Complexity | Notes                       |
| ----------------------- | --------------- | --------------------------- |
| `takeIf` / `takeUnless` | O(1) | Constant time, just a check |

Safe Access & Null Handling

val arr = listOf(10, 20)
val second = arr.getOrNull(1) // returns null if out of bounds

Real-world: Avoid IndexOutOfBoundsException safely.

| Function    | Time Complexity | Notes                            |
| ----------- | --------------- | -------------------------------- |
| `getOrNull` | O(1) | Constant-time, avoids exceptions |

Infinite / Functional Sequences: generateSequence

val fib = generateSequence(Pair(0,1)) { Pair(it.second, it.first+it.second) }
.map { it.first }
.take(10)
.toList()
println(fib) // [0,1,1,2,3,5,8,13,21,34]

Real-world: Fibonacci, lazy event streams, infinite generators.

| Function           | Time Complexity  | Notes                             |
| ------------------ | ---------------- | --------------------------------- |
| `generateSequence` | O(1) per element | Lazy, infinite sequences possible |

Cheat Sheet ❤️

If you have reached till here, hoping you found this blog useful 🙌🏻.

Happy Learning!


Kotlin Idiomatic Collections — The Ultimate Guide was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.

 

Web Developer, Web Design, Web Builder, Project Manager, Business Analyst, .Net Developer

No Comments

This Post Has 0 Comments

Leave a Reply

Back To Top