Rik
Rik

Reputation: 828

In Kotlin, how do I idiomatically access nullable nested map values, or return a default?

Quick Kotlin best practices question, as I couldn't really work out the best way to do this from the documentation.

Assume I have the following nested map (typing specified explicitly for the purpose of this question):

val userWidgetCount: Map<String, Map<String, Int>> = mapOf(
        "rikbrown" to mapOf(
                "widgetTypeA" to 1,
                "widgetTypeB" to 2))

Can the following mode be any more succinct?

 fun getUserWidgetCount(username: String, widgetType: String): Int {
    return userWidgetCount[username]?.get(widgetType)?:0
}

In other words, I want to return the user widget count iff the user is known and they have an entry for that widget type, otherwise zero. In particular I saw I can use [] syntax to access the map initially, but I couldn't see a way to do this at the second level after using ?..

Upvotes: 4

Views: 5319

Answers (1)

Yoav Sternberg
Yoav Sternberg

Reputation: 6861

I would use an extension operator method for that.

// Option 1
operator fun <K, V> Map<K, V>?.get(key: K) = this?.get(key)
// Option 2
operator fun <K, K2, V> Map<K, Map<K2, V>>.get(key1: K, key2: K2): V? = get(key1)?.get(key2)

Option 1:

Define an extension that provides get operator for nullable map. In Kotlin's stdlib such approach appears with Any?.toString() extension method.

fun getUserWidgetCount(username: String, widgetType: String): Int {
    return userWidgetCount[username][widgetType] ?: 0
}

Option 2:

Create a special extension for map of maps. In my opinion, it is better because it shows the contract of the map of maps better than two gets in a row.

fun getUserWidgetCount(username: String, widgetType: String): Int {
    return userWidgetCount[username, widgetType] ?: 0
}

Upvotes: 6

Related Questions