Collection processing is one of the most useful applications of functional programming. One procedure that developers follow during the collection process is filtering; in this article, we’ll explore the fundamentals of complex Kotlin filtering operations that you can adopt for Android development.
To follow along with this tutorial, you’ll need basic knowledge of Kotlin and either Android Studio or IntelliJ IDE installed on your machine. Let’s get started!
Jump ahead:
filter()
operatorfilter()
operator work?
filter()
operatorfilter()
operatorMap
filter()
operatorAs developers, we transform, manipulate, and filter data on a regular basis; to make this task easier, we can use Kotlin collection operations. When working with data or collection elements in Kotlin, you have to use either the Set
, Map
, or filter()
operator to manipulate data.
You have to use predicates to define the filtering collection when using the Kotlin filter()
operator. For example, a lambda function takes a collection element and returns a boolean value, which can be either TRUE
or FALSE
. A returned value of TRUE
implies that the given element matches the predicate, and FALSE
implies that the value doesn’t match. Below are some definitions that will come in handy throughout the rest of this article:
filter()
: A type of collection operation that is used to filter out desired elements from a collection setMap
: A type of collection operation that is used to modify elements and perform operationsList
: A generic collection of items on which you can run built-in functions, including containsAll
, contains
, get
, indexOf
, listOf
, isEmpty
, and iterator
Predicate
: Used to determine if a condition returns TRUE
or FALSE
; examples include all
, any
, count
, and find
Array
: A row of values, a column of values, or both rows and columns of values combinedfilter()
operator work?With the filter()
operator, you can set a given condition to filter a set of data. Let’s review the different ways to implement the filter()
operator.
Filtering by predicate entails using the basic filter()
command with a predicate that returns a list of elements matching the predicate’s conditions. You can choose to filter elements by predicate using a List
, Set
, or Map
. Other commands include filterNotNull
, filterIndexed
, filterNot
, and filterIsInstance
, which we’ll explore in detail later in the article.
partition()
We can use Kotlin’s partition()
command to filter all the elements that don’t match the predicate’s condition and put them in a separate list.
In Kotlin, test predicates are sets of commands used to evaluate a given set of data to determine whether they match a given predicate’s conditions, for example, TRUE
or FALSE
, empty values, and null values. These functions simply test predicates against some collection elements. Some examples include any()
, all()
, and none()
.
filter()
operatorThe Kotlin filter()
operator is the most important task in the Kotlin collection operation, allowing you to filter a range of data based on a defined set of criteria. It also assists in checking the predicate in a given list of elements, returning the filtered values. The filter()
operator modifies and transforms the data into a new set of arrays filled with elements that pass the function test. It cannot execute the function for an empty array element and doesn’t change the original array.
filter()
operatorTo transform, manipulate, and filter existing collections, Kotlin provides us with several build transform operators, known as filter operators. The filter()
operator creates a new collection object by iterating over existing collection objects and filtering these objects based on their predicates. Later, these predicates are passed as lambda expressions to the functions being checked for. The example below illustrates this concept:
fun main() { val part1 : collections like List val part2 = part1.filter { --- this contains the condition--- } ---Kotlin logics --- }
The code above shows a list of values in a collection called part1
. This list of items is filtered by passing it against some default conditions using the filter()
command and Kotlin logic, which produces an output that is saved in another variable called part2
that can be retrieved at will. The code snippet below shows how to utilize the filter()
method:
class FilterOperator { /** * This only returns a list of elements that match the given predicate */ public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> { return filterTo(ArrayList<T>(), predicate) } }
One of the basic filter operators is the filter()
function. Let’s consider the code snippet below, which demonstrates how the filter()
function is called to filter the value of even numbers from a set of numerical data:
val no: List<Int> = listOf(1,2,3,4,5,6,7,8,9,10,11,12) val positiveEvenNumbers = no.filter { it % 2 == 0 } print(positiveEvenNumbers) // [2,4,6,8,10,12]
The following result shows the even number values from the list of numbers above:
[2,4,6,8,10,12]
From the result above, it is evident that the returned list contains only elements matching the predicate.
Next, we’ll learn how to implement some advanced filter operators using a List
and Map
. We’ll learn how to retrieve the overlapping items from two different lists where two or more variables are passed in the lambda function. We can use the filter()
operator to check the predicate against elements over a list and return a modified list of items.
filterIndexed
filterIndexed
is an advanced Kotlin filter operator used to return a list of elements that match only the given predicate condition. The code below shows the syntax:
/** * this only returns a list containing only elements matching a given predicate */ public inline fun <T> Iterable<T>.filterIndexed(predicate: (index: Int, T) -> Boolean): List<T> { return filterIndexedTo(ArrayList<T>(), predicate) }
The basic filter operator is the filter()
command, while the filterIndexed
operator filters the set of values of the collection in the lambda function:
val list = listOf(2,4,6,8,10) val filteredIndexList = list.filterIndexed {index, item -> (index != 0) && (item % 2 == 0) } println(filteredIndexList)
The code snippet above uses a list of even numbers; it then filters the index value using the filterIndexList
command, assigning an instruction to filter only the even numbers and numbers not equal to zero.
filterIsInstance
filterIsInstance
is an advanced Kotlin operator used to filter out a list of elements that are instances of a particular type:
/** * this only returns a list of items containing elements that are instances of a particular type parameter V * */ public inline fun <reified R> Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer V> { return filterIsInstanceTo(ArrayList<V>()) }
The code below shows an example:
val list = listOf(2, "", false, 9, 8.0, 0.0f) val filteredIsInstanceList = list.filterIsInstance<Int>() println(filteredIsInstanceList)
filterNotNull
filterNotNull
is an advanced Kotlin operator that is used to return a list that contains elements that are not null:
public fun <T : Any> Iterable<T?>.filterNotNull(): List<T> { return filterNotNullTo(ArrayList<T>()) }
The code snippet below includes some elements in the list that are not null, like 90
, 5
, 9
, and 15
. When the filterNotNullList
method is invoked, it filters out the non-null values and returns them from the list:
val list = listOf(90, 5, null, 9, 15, null) val filteredNotNullList = list.filterNotNull() println(filteredNotNullList)
Map
In the case of filtering with maps, there are no filterNotNull
, filterIsInstance
, or filterIndexed
functions like we had with List
earlier. Here, the approach is to filter all keys or values of the map
collection and return the filtered map entities that match the predicate. Also, note that the returned type of the filterKeys
and filterValues
will still be a map:
val map = mapOf("keya" to a, "keyb" to b, "keyc" to c) println(map.filterKeys { key -> key.contains("key") }) println(map.filterValues { value -> value % 2 == 0 })
In this tutorial, we covered the basics of the Kotlin filter()
operation, reviewing its benefits, syntax, and some example code implementations of a few complex and advanced operators. Finally, we covered how to filter items from a given list or maps that satisfy a given predicate condition.
I hope you found this article interesting and helpful. Be sure to leave a comment if you have any questions. Happy coding!
LogRocket is an Android monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your Android apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your Android apps — try LogRocket for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.