Hello all I'm adding entries to a map and I'd like...
# getting-started
m
Hello all I'm adding entries to a map and I'd like to merge the values where the key already exists. For example, if I have:
Copy code
val myMap = mutableMapOf<String, List<String>>()
and try to add:
Copy code
myMap["a"] = listOf("1")
        myMap["a"] = listOf("2")
I'd like to have:
Copy code
"a"=["1","2"]
How can I achieve this? Can I achieve it using an immutable map?
d
You can do something like this:
Copy code
val myMap = mutableMapOf<String, MutableList<String>>().withDefault { mutableListOf() }

myMap["a"]!! += "1"
myMap["a"]!! += listOf("2")
m
This results in a NPE at
myMap["a"]!! += "1"
d
Oh right, you have to use
.getValue("a)
😞
Not a great solution
m
Nope, I was hoping there would be something which allowed me to provide a function to update the value in the case of a duplicate value
d
Probably makes sense to add an extension function of some sort
m
Can you use something like this instead?
Copy code
kotlin
val map = mutableMapOf<String, MutableList<String>>()

map.getOrPut("a") {mutableListOf()}.add("1")
map.getOrPut("a") {mutableListOf()}.add("2")
map.getOrPut("b") {mutableListOf()}.add("3")


map  //{a = [1,2], b [3]}
Where I’d extract the getOrPut into a function
m
Yep, that works. Thanks.
d
That's basically the same thing but it doesn't use
withDefault
Actually, not sure that it is
It might not store the defaults lol, I am tired
m
I agree that it’s basically the same thing. Didn’t know
withDefault
existed on map, so thank you for that. The big difference is my approach only allows adding elements, so if adding/merging a List is a requirement, it doesn’t help. I guess the other difference is
getOrPut
knows that map is not null whereas it appears using
withDefault
doesn’t provide enough information to the compiler so it can know the result of the
get
won’t be null.
Or given the interaction is in a function, there could be multiple functions to wrap the cases. In which case this would /could be a custom class that wraps a Map.
Hmm, was curious, so did a bit more work. Yes, using
withDefault
requires also using
getValue
, so then compiler knows it’s not null BUT doing a
getValue
returns the default, BUT doesn’t add an entry into the map for the missing key.
Copy code
kotlin
val map2 = mutableMapOf<String, MutableList<String>>().withDefault { mutableListOf() }
val value = map2.getValue("a")
value += "1"
val value2 = map2.getValue("a")
value2 += "2"
map2.getValue("b").add("2")

map2
And map 2 is empty, as is value2 after the getValue.