Blog / May 1, 2022 / 5 mins read / By Suneet Agrawal

Filter Operator : Kotlin

The collection is something which is used by almost everyone. It makes our life easy. List, Set and Map are the best examples of them.

To iterate, filter or modify the existing collection object, Kotlin provides us with a few in builds transform operators. Filter operator is one of them.

Lets try to understand the filter operator in detail.

What is filter operator?

Filter operator is used to create a new collection object by iterating over the existing collection object and filtering the elements based on the predicates to it. The predicate that needs to be checked for, is passed as lambda to the function.

Since the filter operator is an extension of the Iterable Interface, it can be used with all three collections ie List, Set and Map.

/**
 * Returns a list containing only elements matching the given [predicate].
 * 
 * @sample samples.collections.Collections.Filtering.filter
 */
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

Filter also has other few functions as below,

  • filterIndexed used for indexed iteration and filter the elements based on the given predicate.
  • filterNot used to filter the elements which did not match the given predicate.
  • filterNotNull used for filtering non-null elements. This doesn’t take any predicate.
  • filterIsInstanceused to filter all the elements which are instance of a particular type. This also doesn’t take any predicate.
/**
 * Returns a list containing only elements matching the given [predicate].
 * @param [predicate] function that takes the index of an element and the element itself
 * and returns the result of predicate evaluation on the element.
 * 
 * @sample samples.collections.Collections.Filtering.filterIndexed
 */
public inline fun <T> Iterable<T>.filterIndexed(predicate: (index: Int, T) -> Boolean): List<T> {
    return filterIndexedTo(ArrayList<T>(), predicate)
}

/**
 * Returns a list containing all elements not matching the given [predicate].
 * 
 * @sample samples.collections.Collections.Filtering.filter
 */
public inline fun <T> Iterable<T>.filterNot(predicate: (T) -> Boolean): List<T>>{
    return filterNotTo(ArrayList<T>(), predicate)
}

/**
 * Returns a list containing all elements that are not `null`.
 * 
 * @sample samples.collections.Collections.Filtering.filterNotNull
 */
public fun <T : Any> Iterable<T?>.filterNotNull(): List<T> {
    return filterNotNullTo(ArrayList<T>())
}

/**
 * Returns a list containing all elements that are instances of specified type parameter R.
 * 
 * @sample samples.collections.Collections.Filtering.filterIsInstance
 */
public inline fun <reified R> Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer R> {
    return filterIsInstanceTo(ArrayList<R>())
}

Filter with List

filter operator can be used over a list to check the predicate on its elements and return the filtered list. It can be used with a named parameter or using it.

val list = listOf(1, 2, 3, 4, 5)
        
val filteredList = list.filter { it % 2 == 0 }
println(filteredList)

val filteredList2 = list.filter { item -> item % 2 == 0 }
println(filteredList2)

val filteredNotList = list.filterNot { item -> item % 2 == 0 }
println(filteredNotList)

In the case of filterIndexed, since we have two variables passed in the lambda function, we can not skip the named parameters.

val list = listOf(1, 2, 3, 4, 5)
    
val filteredIndexList = list.filterIndexed {index, item -> (index != 0) && (item % 2 == 0) }
println(filteredIndexList)

In the case of filterNotNull, it filter outs the null values and return the list of only the non-null values.

val list = listOf(1, null, 3, 4, 5, null)

val filteredNotNullList = list.filterNotNull()
println(filteredNotNullList)

In the case of filterIsInstance, it filter outs and return the list of the elements of particular data type specified.

val list = listOf(1, "", true, 4, 0.0, 0.0f)

val filteredIsInstanceList = list.filterIsInstance<Int>()
println(filteredIsInstanceList)

Filter with Set

Similar to List, filter operator can be used over a set to check the predicate on its elements return the filtered set. It can be used with a named parameter or using it.

val set = setOf(1, 2, 3, 4, 5)

val filterSet = set.filter { it % 2 == 0 }
println(filterSet)

val filterSet2 = set.filter { item -> item % 2 == 0 }
println(filterSet2)

val filterNotSet = set.filterNot { item -> item % 2 == 0 }
println(filterNotSet)

In the case of filterIndexed, since we have two variables passed in the lambda function, we can not skip the named parameters.

val set = setOf(1, 2, 3, 4, 5)
    
val filteredIndexSet = set.filterIndexed {index, item -> (index != 0) && (item % 2 == 0) }
println(filteredIndexSet)

In the case of filterNotNull, it filter outs the null values and return the set of only the non-null values.

val set = setOf(1, null, 3, 4, 5, null)

val filteredNotNullSet = set.filterNotNull()
println(filteredNotNullSet)

In the case of filterIsInstance, it filter outs and return the set of the elements of particular data type specified.

val set = setOf(1, "", true, 4, 0.0, 0.0f)

val filteredIsInstanceSet = set.filterIsInstance<Int>()
println(filteredIsInstanceSet)

Filter with Map

filter operator can be used with map collection similar to the list and set using below functions and named parameters. There are no filterIndexed, filterNotNull and filterIsInstance functions in case of map collection.

val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3)

val filteredMap = map.filter { entity -> entity.key.contains("key") && entity.value % 2 == 0 }
println(filteredMap)

val filteredNotMap = map.filterNot { entity -> !entity.key.contains("key") || entity.value % 2 != 0 }
println(filteredNotMap)

In the case of a filter operator with a map collection, we can also filter all keys or values of the map collection and return the filtered map entites which confirm the predicate.

Please not that the return type of the filterKeys and filterValues will still be a map.

val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3)
    
println(map.filterKeys { key -> key.contains("key") })

println(map.filterValues { value -> value % 2 == 0 })
Comments