Explanation of Functional Operations in Kotlin
Let's get started!
In many programming languages, when we are dealing with collections to process or transform the data, it might be difficult to handle the operations. Kotlins set of functional features are making the code clean and understandable.
Let’s start with some basics.
Mapping and Transformation: map
The map function transforms each element of a collection into a new form through a given lambda expression and return the altered collection as a new collection with keeping the old one.
val numbers = listOf(1, 2, 3, 4, 5)
val squares = numbers.map { it * it }
println(squares) // Output: [1, 4, 9, 16, 25]
Here:
Filtering Data: filter
To keep only elements that obeys to a condition, we should use filter operation
Here is an example
val numbers = listOf(1, 2, 3, 4, 5)
val even = numbers.filter { it % 2 == 0 }
println(even) // Output: [2, 4]
We can also remove elements with filterNot:
val numbers = listOf(1, 2, 3, 4, 5)
val odd = numbers.filterNot { it % 2 == 0 }
println(odd) // Output: [1, 3, 5]
We can chain Functional Operations in Kotlin
We can also chain multiple functional operations to express complex transformations concisely.
val result = (1..10)
.filter { it % 2 == 0 } // keep even numbers
.map { it * it } // square them
.reduce { acc, value -> acc + value } // sum all squares
println(result)
Each step produces a new list (or value) until the final reduction gives a single result. The usage is clean and readable for handling the complex logic step by step.
Flattening Nested Collections with flatMap
Sometimes you have nested lists like this: List< List< T > > and you may want a single flat list of all of these lists. In this case you can use flatMap.
val people = listOf(
listOf("Alice", "Bob"),
listOf("Charlie", "Diana")
)
val flattened = people.flatMap { it }
println(flattened) // Output: [Alice, Bob, Charlie, Diana]
Aggregation with reduce and fold
Both reduce and fold combine elements into a single value. The difference is that fold allows an initial accumulator value and reduce uses the first element as the initial value.
val numbers = listOf(1, 2, 3, 4, 5)
val sum = numbers.reduce { acc, number -> acc + number }
println(sum) // Output: 15
val multply = numbers.fold(1) { acc, number -> acc * number }
println(multply) // Output: 120
Use Sequence when Lazy Evaluation needed
For large datasets, using regular collection operations may create many intermediate lists. Kotlin’s Sequence API perform the evaluation lazily. It means it processes items one-by-one instead of all at once.
val result = generateSequence(1) { it + 1 }
.take(1000)
.filter { it % 2 == 0 }
.map { it * it }
.sum()
println(result)
Normally, the regular operations creates intermediate lists for each of functional operation to perform the next process. But here we use Sequence to make it lazy without creating the intermediate collections. This is memory efficient. This is especially useful when chaining many operations on large inputs.
Functional Operations with Custom Types
You can combine functional operations with Kotlin data classes to manipulate complex data easily.
data class User(val name: String, val age: Int)
val users = listOf(
User("Alice", 28),
User("Bob", 35),
User("Charlie", 22),
)
val adults = users.filter { it.age >= 30 }.map { it.name }
println(adults) // Output: [Bob]
Above, we destructed and filtered the collection of data in a readable and declarative way.
A quick list of what we learned in this article:
That is all.
Burak Hamdi TUFAN