Collect to map skipping null values

Since Kotlin 1.6, there is also a stable buildMap function that can be used to write custom helper functions that are performant without sacrificing readability:

fun <T, K : Any, V : Any> Iterable<T>.associateByNotNull(
    keySelector: (T) -> K?,
    valueTransform: (T) -> V?,
): Map<K, V> = buildMap {
    for (item in this@associateByNotNull) {
        val key = keySelector(item) ?: continue
        val value = valueTransform(item) ?: continue
        this[key] = value
    }
}

Note that writing this as a "low-level" for loop eliminates the need for the creation of intermediate collections.


Actually, a slight change to pwolaq's answer guarantees that the second item is non-nullable:

val map = listOf(Pair("a", 1), Pair("b", null), Pair("c", 3), Pair("d", null))
    .mapNotNull { p -> p.second?.let { Pair(p.first, it) } }
    .toMap()
println(map)

This will give you a Map<String, Int>, since mapNotNull ignores anything that maps to null, and using let with the safe call operator ?. returns null if its receiver (p.second) is null.

This is basically what you stated in your question, made shorter with let.


You want to filter out null values, then you should use filter method:

val map = listOf(Pair("a", 1), Pair("b", null), Pair("c", 3), Pair("d", null))
    .filter { it.second != null }
    .toMap()
println(map)

Tags:

Kotlin