Course Content
Android Development with Kotlin
Android Development with Kotlin
Filtering and Modifying Lists
While studying lists, you might have wondered how to filter or modify a specific collection quickly.
For example, let's say we have a list of numbers, and we want to find the square of each element in the list.
Note
The square of a number is the number multiplied by itself once. For instance, if we have the number
5
, the square of that number will be5 * 5 = 25
.
Main
fun main() { val numbers: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8) val squareNumbers: MutableList<Int> = mutableListOf() for (number in numbers) { squareNumbers.add(number * number) } println("Initial list: $numbers") println("List of squares: $squareNumbers") }
You can use a loop to create a new list with the squares of numbers.
But did you know that Kotlin allows you to do this without using a loop and in just one line?
.map() Method
Please don’t confuse this method with a data structure!
The map
method in Kotlin is a very handy tool for transforming collections. It can be applied to lists (List
), sets (Set
), and other collections.
Using it is very simple. Let’s look at an example of creating a list with the squares of numbers, as we did above:
Main
fun main() { val numbers: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8) val squareNumbers: List<Int> = numbers.map { it * 2 }.toList() println("Initial list: $numbers") println("List of squares: $squareNumbers") }
Let's break down how it works step by step:
Briefly About Lambda Expressions
Lambda expressions in the context of lists are used to easily and quickly define what to do with each element of the list. This allows you to apply the same operation to all elements of the list without creating separate functions.
Let's say you have a list of numbers, and you want to create a new list where each number is increased by 2. Instead of writing a loop or a separate function, you can use a lambda expression with the map
method.
Main
val numbers = listOf(1, 2, 3, 4) val increasedNumbers = numbers.map { it + 2 }
Here, numbers
is the original list of numbers. The map
method takes each element from numbers
and applies the lambda expression { it + 2 }
to it. In this lambda expression, it
refers to the current element from the list, and the operation it + 2
increases it by 2. The result is a new list, increasedNumbers
, containing [3, 4, 5, 6]
.
Advantages
Using lambda expressions in these cases allows you to:
- Avoid creating intermediate variables and complex loops;
- Write code that is easy to read and understand;
- Perform operations on list elements directly without creating additional functions.
We can use the .map()
method for many operations, and it's very simple to use.
For example, let's transform a list of type Int
into a list of type String
:
Main
fun main() { val numbers: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8) val stringNumbers: List<String> = numbers.map { "Number $it" } println("Initial list: $numbers") println("String list: $stringNumbers") }
Here, we've demonstrated a more complex operation on list elements, clearly indicating that we want to see a list of strings in the format "Number \
element`"`.
We could do the same with loops or functions, but why bother when we can achieve it in one simple line?
We can perform similar operations with sets and arrays; let's look at an example:
Main
fun main() { val numbersList: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8) val doubledNumbers: List<Int> = numbersList.map { it * 2 } val numbersArray: Array<Int> = arrayOf(1, 5, 10, 23, 61) val tripleNumbers: Array<Int> = numbersArray.map { it * 3 }.toTypedArray() val numbersSet: Set<Int> = setOf(38, 19, 22, 41, 20) val stringSet: Set<String> = numbersSet.map { "Number $it" }.toSet() println("Initial list: $numbersList") println("Doubled list: $doubledNumbers") println() println("Initial array: ${numbersArray.joinToString(" ")}") println("Tripled Array: ${tripleNumbers.joinToString (" ")}") println() println("Initial Set: $numbersSet") println("String Set: $stringSet") }
We can also use the map
method with a Map
, but to do this, we need to convert the map to a list, either by extracting the list of keys using the keys
property or the list of values using the values
property.
Let's look at an example where the keys are of type Int
and the values are of type String
, and we'll extract a list of transformed keys and values:
Main
fun main() { val exampleMap: Map<Int, String> = mapOf(1 to "One", 2 to "Two", 3 to "Three", 4 to "Four") val modifiedKeys: List<Int> = exampleMap.keys.map { it * 2 } val modifiedValues: List<String> = exampleMap.values.map { "Value: $it" } println("Modified keys: $modifiedKeys") println("Modified values: $modifiedValues") }
This way, we can easily modify lists of keys and values in a map using the map method!
Filtration Methods
Filtering lists is also a very useful feature in Kotlin, so let's look at how it works.
Filtering uses the .filter()
method, which takes a lambda expression (just like the map
method), but these lambda expressions must return a boolean value. So, the expressions should be like "it > 2
" or "it.length <= 10
" and so on.
Let's look at an example where we filter a list of numbers to keep only those that are divisible by 2 (even numbers only):
Main
fun main() { val numbersList: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8, 19, 28, 48, 11, 92, 10, 2, 1, 38, 19, 34, 25, 132) val evenNumbersList: List<Int> = numbersList.filter { it % 2 == 0 } println("Initial list: $numbersList") println("Only even numbers list: $evenNumbersList") }
it % 2 == 0
means that the remainder of the division by 2 is 0, meaning the number is evenly divisible by 2.
You can also filter using simpler conditions.
For example, if we want the list to contain numbers that are strictly greater than 30, the filtering in the code would look like this:
Main
fun main() { val numbersList: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8, 19, 28, 48, 11, 92, 10, 2, 1, 38, 19, 34, 25, 132) val filteredNumbersList: List<Int> = numbersList.filter { it > 30 } println("Initial list: $numbersList") println("Only even numbers list: $filteredNumbersList") }
As you can see, only numbers strictly greater than 30 remain. So our filtering works successfully! Great!
Similar methods work with Sets and arrays. With a Map, we’ll need to complicate the lambda expression a bit, but it’s not difficult and works just like a for
loop.
We need to specify both the key and value inside the lambda expression and then indicate what we want to filter:
Main
fun main() { val exampleMap: Map<Int, String> = mapOf(1 to "One", 2 to "Two", 3 to "Three", 4 to "Four", 5 to "Five") val filteredMap: Map<Int, String> = exampleMap.filter { (key, value) -> key % 2 == 0 && value.length > 3} println(filteredMap) }
Here, the lambda expression is a bit more complex because it uses an arrow after defining the parameters.
We specify the key
and value
in parentheses, and then after the arrow (->
), we provide a boolean expression that tells us the key must be even and the value must have a length strictly greater than 3.
In this way, we can use filtering on lists, arrays, sets, and maps. Great!
Note
It's okay if some points are unclear to you right now; with practice, everything will become more accessible, and you'll master all these methods perfectly!
Sorting Collections
For completeness, it's worth mentioning two important methods: sorted()
and sortedDescending()
. As you can infer from the names, the first method sorts a List
, Array
, or Set
in ascending order, while the second sorts them in descending order.
The operation is incredibly simple! Let's look at an example:
Main
fun main() { val numbersList: List<Int> = listOf(2, 1, 5, 6, 7, 3, 4, 8, 19, 28, 48, 11, 92, 10, 2, 1, 38, 19, 34, 25, 132) val sortedListAsc: List<Int> = numbersList.sorted() val sortedListDesc: List<Int> = numbersList.sortedDescending() println("Initial list: $numbersList") println("Sorted in Ascending order: $sortedListAsc") println("Sorted in Descending order: $sortedListDesc") }
Summary
This simple approach allows us to modify, filter, and sort various types of collections!
Thanks for your feedback!