如何在Kotlin中迭代嵌套的HashMap?

x8diyxa7  于 2023-01-26  发布在  Kotlin
关注(0)|答案(2)|浏览(165)

我是Kotlin的新手,我很难找到一种惯用的方法来将下面的Python代码片段翻译成Kotlin。假设我有一个单词列表,我试图将其插入到Trie数据结构中,在Python中表示为嵌套字典。Trie中的终端节点将通过向字典的该层添加键#来标记。

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

对于输入词:["test","this","trie"],您将得到以下表示形式:

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

我在Kotlin尝试过以下方法:

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()
}

但是,这会导致以下编译错误:

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

我知道我可以显式地创建Node对象,其中包含一个指向其他Node的HashMap来表示Trie,但是我感兴趣的是了解是否有一种方法可以将Trie表示为Kotlin中的HashMap的HashMap,就像我在Python中所做的那样。

cmssoen2

cmssoen21#

是的,以牺牲所有类型的安全为代价。
强调一下,你在问题中指出的是正确的方法。你绝对应该创建一个Node数据类,其中包含一个指向额外节点的散列表。这是这个工作的正确递归数据结构。下面是解决这个问题的错误方法。
但是你需要一个无限嵌套的散列表,如果值类型是Any,我们可以把任何数据存储到HashMap中。

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

现在Kotlin几乎没有足够的类型信息来计算内部Map的样子,所以我们必须给它们添加注解。

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

以及

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

最后,当我们“放大”一个嵌套的map时,我们会得到一个Any,我们只是悄悄地把它castMutableMap<Char, Any>,没有人会注意到。

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

完整示例:

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)
}
uidvcgyl

uidvcgyl2#

将Silvio的答案解释为类型安全版本的可能性:

val words = listOf("test", "this", "trie")

data class Node(
  var char: Char? = null,
  val children: MutableMap<Char, Node> = mutableMapOf()
) {
  override fun toString(): String = children.onEach { it.toString() }.toString()
}

val root = Node()

words.forEach { word ->
  var currentNode = root
  word.forEach { char ->
    if (!currentNode.children.contains(char)) {
      currentNode.children[char] = Node(char)
    }
    currentNode = currentNode.children[char]!!
  }
  currentNode.children['#'] = Node()
}

println(root)

// Output: {t={e={s={t={#={}}}}, h={i={s={#={}}}}, r={i={e={#={}}}}}}

相关问题