Reputation: 60081
I can convert a List<Int?>
to List<Int>
using mapNotNull
function as shown below.
@Test
fun main() {
val testData = listOf(1, null, 3, null)
val noNull = processAwayNull(testData)
}
private fun processAwayNull(testData: List<Int?>): List<Int> {
return testData.mapNotNull{ it }
}
How could I convert Map<String, Int?>
to Map<String, Int>
?
The below with testData.filter { it.value != null }
doesn't works, as it still produce Map<String, Int?>
.
@Test
fun main() {
val testData = mapOf("One" to 1, "Two" to null, "Three" to 3, "Four" to null)
val noNull = processAwayNull(testData)
}
private fun processAwayNull(testData: Map<String, Int?>): Map<String, Int> {
return testData.filter { it.value != null }
}
Upvotes: 2
Views: 1450
Reputation: 26170
Possible alternative with custom helper function:
inline fun <K, V, R> Map<K, V>.mapValuesNotNullToMap(transformValue: (V) -> R?): Map<K, R> =
buildMap {
[email protected] { (key, value) ->
transformValue(value)?.let { put(key, it) }
}
}
Upvotes: 0
Reputation: 23242
Well, not really out of the box (in the sense that you get Map<String, Int>
immediately), but what about filterValues
?
testData.filterValues { it != null } // gives Map<String, Int?> but without null-values
Combining or replacing that with mapValues
(maybe you can use a default value instead of null
?):
// combining:
testData.filterValues { it != null }
.mapValues { (_, value) -> value as Int }
// replacing:
testData.mapValues { (_, value) -> value ?: /* default value */ 0 }
Both give a Map<String, Int>
but the first creates and fills 2 maps under the hood and the second uses 0
instead of null
.
You can also simplify the filterValues
-variant with an appropriate unchecked cast, as "we know it better":
testData.filterValues { it != null } as Map<String, Int> // unchecked cast, because: we really do know better, do we? ;-)
Alternatively, you could also just handle all entries the way you knew already (using mapNotNull
) and then create a new map out of it:
testData.asSequence()
.mapNotNull { (key, value) ->
value?.let {
key to it
}
}
.toMap() // giving Map<String, Int>
If you require that more often you may even want to have your own extension function in place:
@Suppress("UNCHECKED_CAST")
fun <K, V> Map<K, V?>.filterValuesNotNull() = filterValues { it != null } as Map<K, V>
Now you can use it similar as to follows:
testData.filterValuesNotNull() // giving Map<String, Int>
Upvotes: 5