'How to use withDefault wrappers?
I want to use MutableMap with defaults:
val myMap = mutableMapOf<String, Set<String>>().withDefault { mutableSetOf() }
but I can't use getOrImplicitDefault method because withDefault returns MutableMap<String, Set<String>> type. Moreover, I can't cast to MutableMapWithDefault interface because this is a private interface.
I can't use get method either because it returns a nullable type. It is ok because this is a method on the MutableMap interface (moreover it doesn't call defaultValue callback for take default value).
Seems like this functionality is not correctly implemented in Kotlin, or I am using it wrong. So, how do I use withDefault wrappers correctly?
Solution 1:[1]
As of Kotlin 1.0 a wrapper returned by withDefault is only usable in property delegation use cases.
val map = mutableMapOf<String, Set<String>>().withDefault { mutableSetOf() }
var property: Set<String> by map // returns empty set by default
Solution 2:[2]
Looks like in Kotlin 1.1 this actually works if you use the getValue() function instead of the get() function.
Solution 3:[3]
I've been looking for a way to return default value from a MutableMap, but also store it at the same time for future retrieval. The .withDefault only returns the default value, but doesn't store it. Calling .getOrPut every time I need to retrieve a value doesn't look like a good idea. I've came up with something like this:
val myMap = with(mutableMapOf<String, Set<String>>()) {
withDefault { key -> getOrPut(key, { mutableSetOf<String>() }) }
}
This calls getOrPut within withDefault wrapper on the backing MutableMap object, which puts the missing key-value pair into the map and returns it.
To encapsulate the behaviour you can create a delegated property provider.
/** Wraps a [MutableMap]. Will generate a [defaultValue] if none exists, and set it into the map. */
fun <K, V> mapWithPutDefault(defaultValue: (key: K) -> V): ReadWriteProperty<Any?, MutableMap<K, V>> =
object : ReadWriteProperty<Any?, MutableMap<K, V>> {
private var map: MutableMap<K, V> = with(mutableMapOf<K, V>()) {
withDefault { key -> getOrPut(key) { defaultValue(key) } }
}
override fun getValue(thisRef: Any?, property: KProperty<*>): MutableMap<K, V> = map
override fun setValue(thisRef: Any?, property: KProperty<*>, value: MutableMap<K, V>) {
this.map = value
}
}
fun main() {
val myMap: MutableMap<String, String> by mapWithPutDefault { "some default value for $it" }
println("map is empty: $myMap")
// map is empty: {}
val someValue = myMap.getValue("my-key")
println("map returns a default value: $someValue")
// map returns a default value: some default value for my-key
println("map now has a value: $myMap")
// map now has a value: {my-key=some default value for my-key}
}
Solution 4:[4]
Map withDefault returns a wrapper of the read-only map, having the implicit default value provided with the specified function defaultValue. This implicit default value is used when the original map doesn't contain a value for the key specified. See the usage of getOrElse & getOrDefault as well that works the same way as for lists -
val emojiMap = mapOf("Grinning Face" to "?", "Winking face" to "?",
"Zany face" to "?").withDefault({"?"})
fun main()
{
println(emojiMap) // {Grinning Face=?, Winking face=?, Zany face=?}
println(emojiMap.getValue("Grinning Face")) // ?
println(emojiMap.getValue("Zany face")) // ?
println(emojiMap.getValue("Smiling face")) // ?
// getOrElse & getOrDefault
println(emojiMap.getOrElse("Flushed face"){"?"}) // ?
println(emojiMap.getOrDefault("Sad face","?")) // ?
}
Solution 5:[5]
Use the following method:
myMap.getOrPut(someKey,{DEFAULT_VALUE})
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/get-or-put.html
Solution 6:[6]
Well, all the implementations of getOrImplicitDefault redirect t to getOrElseNullable. Maybe try that.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | sschuberth |
| Solution 3 | aSemy |
| Solution 4 | Anoop M Maddasseri |
| Solution 5 | nz_21 |
| Solution 6 | Jacob Zimmerman |
