如何在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 注释适用于我的代码中的某个位置(猜猜在哪里?)。还有模式匹配的默认情况(您可以构建一个破坏我的功能的测试用例来找出原因)。