I'm trying to write a function that maps a String and Int? into a pair, then filters for non null second values in the pair, before continuing to map.
My code looks like this:
val ids: List<String> = listOf("a", "b", "c")
val ints: Map<String, Int?> = mapOf("a" to 1, "b" to 2, "c" to null)
ids.map { id: String ->
Pair(id, ints[id])
}.filter { pair -> pair.second != null}.map { pair: Pair<String, Int> ->
func(id, pair.second)
}
The problem is that the second map has the error:
Type inference failed: Cannot infer type parameter T in
inline fun <T, R> kotlin.collections.Iterable<T>.map ( transform (T) -> R ): kotlin.collections.List<R>
This looks like because the compiler does not know to smart cast my Iterable<Pair<String, Int?>>
into an Iterable<Pair<String, Int>>
after my filter
. What can I do instead to solve this?
Kotlin's smart cast is usually not applicable outside method boundaries. However, there are a couple of ways you can achieve your goal anyway.
First, you can simply tell the compiler that the second value of the pair is never null by using the !!
operator like so:
ids.map { id: String -> Pair(id, ints[id]) }
.filter { pair -> pair.second != null }
.map { pair: Pair<String, Int?> -> func(pair.second!!) }
Second, you can reverse the order of filter
and map
and apply the !!
operator earlier:
ids.filter { id: String -> ints[id] != null }
.map { id: String -> id to ints[id]!! } //equivalent to Pair(id, ints[id]!!)
.map { pair: Pair<String, Int> -> func(pair.second) }
Finally, you can make it work without the !!
operator by combining the filtering and the mapping in one step using the mapNotNull
extension method:
ids.mapNotNull { id: String -> ints[id]?.let { id to it } }
.map { pair: Pair<String, Int> -> func(pair.second) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With