hi all, I've the following nested maps: `Map<St...
# getting-started
a
hi all, I've the following nested maps:
Map<String, Map<String, Map<String, Int>>>
and I'm trying to access it by nesting
if
statements. I am trying to increment the value (
Int
) to one provided as argument to a function. In doing so, I'm encountering an issue:
No set method providing array access
when trying to do something like:
Copy code
val keyMap = cls.parameter!!["key"] as Map<*, *>
// logic here to increment the value of the last key in the nested map
keyMap[nestedKey1][key] = new_value
the last statement is the one failing with the error shown above my questions are: 1. how can I access nested maps in a safe manner and when I detect a key not existing, create it and nest in that if statement creating the rest of the map? 2. how can I set the map on an object (
cls.parameter
) such that I preserve other existing mappings and do not override with the new (and what would be the only if written) mapping?
1
👍 1
r
The innermost map needs to be mutable in order to set the value. That is, you need
Map<String, Map<String, MutableMap<String, Int>>>
a
Thanks. I've modified all
Map<
to `MutableMap<`and now I'm encountering the issue where I'm trying to access the key in order to set its value. E.g.
map[key1][key2][key3] = value
. In fact what I'm trying to do is Python equivalent of
map[key1][key2][key3] += value
. How can I achieve this value update for the innermost map and set it on a object while preserving the rest of the keys in the nested map?
r
In Python,
map[key]
will throw if the key isn't in the map, whereas in Kotlin it will just return
null
. You can work around this using other functions, but it won't be as pretty. Here's one example (not sure if there's a cleaner one):
Copy code
map.getValue(key1).getValue(key2).let { it[key] = it.getOrDefault(key3, 0) + 1 }
a
Right! What I'm trying is
map!![key1]?.get(key2)
and I get an error on key2. Even though it's defined as a nested
MutableMap
.
r
What kind of error are you getting? It works for me: https://pl.kotl.in/EqlOoXvHx
a
Nevermind. Just implemented the way you coded it and it works. I have a question: what if
getValue(key2)
returns null? will the lambda create it? or do I have to deal with this case before calling the setting of the value?
r
No, it will throw like Python
👍 1
a
I see. How to create non-existing keys in the nested mapping for each level?
r
Something like
Copy code
map.getOrPut(key1) { mutableMapOf() }
    .getOrPut(key2) { mutableMapOf() }
    .let { it[key3] = it.getOrDefault(key3, 0) + 1 }
👍 1
thank you color 1
You can also look into the
withDefault
function, but that doesn't actually clean up the API at all, just eliminates the chance of throwing. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/with-default.html
👍 1
a
Thanks! Will report back should I encounter any issues.
k
Looks like you are fighting against type system. What domain are you trying to model? Is it some config in json/xml? You might want to create your generic class which can hold values of different types, provides type safe access/creation/defaults and supports nesting