如何将嵌套映射作为点分隔scala中键和值的字符串

时间:2017-09-18 16:41:56

标签: scala scala-collections

我有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)

1 个答案:

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