我有Map[String, Any]
。该值可以是另一个Map
,依此类推。
val m: Map[String, Any] = Map("a" -> Map("b" -> Map("c" -> 1, "d" -> 4)))
将此嵌套Map
转换为另一个Map
的最佳方式是什么,其值为
Map("a.b.c" -> 1, "a.b.d" -> 4)
答案 0 :(得分:3)
只需像任何其他编程语言一样使用递归(这不是特定于Scala的东西)。
val m: Map[String, Any] = Map("a" -> Map("b" -> Map("c" -> 1, "d" -> 4)))
def traverse(el: Any, acc: List[String] = List.empty[String]): Map[String, Int] = el match {
case leaf: Int => Map(acc.reverse.mkString(".") -> leaf)
case m: Map[String, Any] => m flatMap {
case (k, v) => traverse(v, k :: acc)
}
}
traverse(m)
res2_2: Map[String, Int] = Map("a.b.c" -> 1, "a.b.d" -> 4)
顺便说一句,
1)所提出的解决方案不是尾递归的(因此可能会在非常深的树上抛出堆栈溢出) - 您可以编写尾递归版本作为练习。提示 - 你需要一个累加器来进行最终的收集(或使用可变缓冲区,idn,也许你不是真的进入函数式编程,并被雇主强迫使用Scala :)。
2)List
是累加器的不合适的结构(co performance),我只是懒得使用不太常见的,因为你懒得尝试至少以某种方式实现这个简单的算法。我打赌在SO上应该有一个重复的问题,但是再一次,懒得去寻找它:)。
3)@unchecked
注释适用于我的代码中的某个位置(猜猜在哪里?)。还有模式匹配的默认情况(你可以构建一个测试用例来破坏我的功能以找出原因)。