如何在scala中将嵌套映射作为点分隔的键和值字符串
How to make a nested map as dot separated strings of key and value in scala
我有一个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)
就像在任何其他编程语言中一样使用递归(它不是 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
是不适合累加器的结构(performance 的原因),我只是懒得使用不太常见的结构,因为你懒得尝试至少以某种方式实现这个微不足道的算法。我敢打赌,关于 SO 应该有一个重复的问题,但还是懒得去找了:)。
3) @unchecked
注释适用于我的代码中的某个位置(猜猜在哪里?)。还有模式匹配的默认情况(您可以构建一个破坏我的功能的测试用例来找出原因)。
我有一个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)
就像在任何其他编程语言中一样使用递归(它不是 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
是不适合累加器的结构(performance 的原因),我只是懒得使用不太常见的结构,因为你懒得尝试至少以某种方式实现这个微不足道的算法。我敢打赌,关于 SO 应该有一个重复的问题,但还是懒得去找了:)。
3) @unchecked
注释适用于我的代码中的某个位置(猜猜在哪里?)。还有模式匹配的默认情况(您可以构建一个破坏我的功能的测试用例来找出原因)。