Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I iterate through nested HashMaps in Kotlin?

I am new to Kotlin, and I am having trouble finding an idiomatic way to translate the snippet of Python below into Kotlin.
Let’s say that I have a list of words that I am trying to insert into a Trie data structure, represented as nested dictionaries in Python. Terminal nodes in the Trie will be marked simply by adding the key # to that level of the dictionary.

trie = {}
for word in words:
    cur = trie
    for letter in word:
        if letter not in cur:
            cur[letter] = {}
        cur = cur[letter]
    cur['#'] = {}

For the input words:
["test","this","trie"]
you would get the following representation:

{'t': {'e': {'s': {'t': {'#': {}}}}, 'h': {'i': {'s': {'#': {}}}}, 'r': {'i': {'e': {'#': {}}}}}}

I have tried the following, in Kotlin:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

val trie: MutableMap<Char, MutableMap<Char, Any>> = mutableMapOf()
for (word in words) {
    var cur = trie
    for (letter in word) {
        if (!cur.containsKey(letter)) {
            cur[letter] = mutableMapOf()
        }
        cur = cur[letter]
    }
    cur['#'] = mutableMapOf()
}

However, this gets me the following compilation error:

error: type mismatch: inferred type is MutableMap<Char, Any>? but MutableMap<Char, MutableMap<Char, Any>> was expected
        cur = cur[letter]

I am aware that I could explicitly create Node objects which contain a HashMap pointing to other Nodes to represent the Trie, however I am interested in understanding if there would be a way to represent the Trie as a HashMap of HashMaps in Kotlin as I did above in Python.

>Solution :

Yes, at the cost of all type safety.

Just to emphasize, what you’ve already pointed out in your question is the correct approach. You should absolutely make a Node dataclass that contains a hashmap pointing to the additional nodes. This is the correct recursive data structure for this job. What follows is the wrong way to solve this problem.

But you asked for an infinitely nested hashmap. We can always store whatever data we want into a HashMap if the value type is Any.

val trie: MutableMap<Char, Any> = mutableMapOf()

Now Kotlin doesn’t have nearly enough type information to figure out what our inner maps look like, so we have to add annotations to those.

cur[letter] = mutableMapOf<Char, Any>()

and

cur['#'] = mutableMapOf<Char, Any>()

Finally, when we "zoom in" on a nested map, we’ll get an Any. We’re just going to quietly cast that to MutableMap<Char, Any>, and nobody will notice.

cur = cur[letter] as MutableMap<Char, Any>

Complete example:

fun main(args: Array<String>) {
  val words = listOf("test", "this", "trie")
  val trie: MutableMap<Char, Any> = mutableMapOf()
  for (word in words) {
    var cur = trie
    for (letter in word) {
      if (!cur.containsKey(letter)) {
        cur[letter] = mutableMapOf<Char, Any>()
      }
      cur = cur[letter] as MutableMap<Char, Any>
    }
    cur['#'] = mutableMapOf<Char, Any>()
  }
  println(trie)
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading