Scala地图转换

时间:2013-03-09 18:44:32

标签: scala scala-collections scala-2.10 scala-2.9

有人可以推荐一种功能性方法来转换下面指定的地图

Map("host.config.autoStart.powerInfo[1].startOrder" -> -1,
    "host.config.autoStart.powerInfo[1].startAction" ->  "None",
    "host.config.autoStart.powerInfo[1].key" ->  "vm-XXX",
    "host.config.autoStart.powerInfo[0].key" ->  "vm-YYY",
    "host.config.autoStart.powerInfo[0].startOrder" ->  -1,
    "host.config.autoStart.powerInfo[0].startAction" ->  "None")

Map("host.config.autoStart.powerInfo" -> Map(
        1 -> Map("startOrder" -> -1,
                "startAction" -> "None",
                "key" -> "vm-639"),
        0 -> Map("startOrder" -> -1,
                "startAction" -> "None",
                "key" -> "vm-641")))
  1. 提取下标前的内容并将其设为密钥
  2. 提取下标[x]之间的数字,并使其成为值
  3. 的键

2 个答案:

答案 0 :(得分:3)

一行(长)解决方案:

val R = """([^\[]+)\[(\d+)\]\.(.+)""".r
m.map{ case(R(h,i,k),v) => (h,i,k,v) }.groupBy(_._1).mapValues(_.groupBy(_._2).mapValues{ _.map{case(h,i,k,v) => (k,v)}.toMap} )
res1: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Any]]] = 
Map(host.config.autoStart.powerInfo -> 
  Map(1 -> Map(startAction -> None, 
               startOrder -> -1, 
               key -> vm-XXX), 
      0 -> Map(key -> vm-YYY, 
      startAction -> None, 
      startOrder -> -1)
))

或者写得或多或少可读:

m.map{ case(R(h,i,k),v) => (h,i,k,v) }
 .groupBy(_._1).mapValues{ value =>
   value.groupBy(_._2).mapValues{ _.map{case(h,i,k,v) => (k,v)}.toMap}
 }

答案 1 :(得分:2)

编辑:在代码中添加了一些注释,以便更容易看到正在发生的事情

从我的REPL复制:

scala> val re = """(.+)\[(\d+)\]\.(.+)""".r // Creates a regex to grab the key values
re: scala.util.matching.Regex = (.+)\[(\d+)\]\.(.+)

scala> val m = Map("host.config.autoStart.powerInfo[1].startOrder" -> -1,"host.config.autoStart.powerInfo[1].startAction" -> "None","host.config.autoStart.powerInfo[1].key" -> "vm-XXX","host.config.autoStart.powerInfo[0].key" -> "vm-YYY","host.config.autoStart.powerInfo[0].startOrder" -> -1,"host.config.autoStart.powerInfo[0].startAction" -> "None")
m: scala.collection.immutable.Map[String,Any] = Map(host.config.autoStart.powerInfo[0].key -> vm-YYY, host.config.autoStart.powerInfo[0].startAction -> None, host.config.autoStart.powerInfo[0].startOrder -> -1, host.config.autoStart.powerInfo[1].startAction -> None, host.config.autoStart.powerInfo[1].startOrder -> -1, host.config.autoStart.powerInfo[1].key -> vm-XXX)

scala> val tempList = m map { // Construct a temporary list of Tuples with all relevant values
     | case (key, value) => key match {
     |    case re(p, i, k) => (p, i, k, value)
     | }}
tempList: scala.collection.immutable.Iterable[(String, String, String, Any)] = List((host.config.autoStart.powerInfo,0,key,vm-YYY), (host.config.autoStart.powerInfo,0,startAction,None), (host.config.autoStart.powerInfo,0,startOrder,-1), (host.config.autoStart.powerInfo,1,startAction,None), (host.config.autoStart.powerInfo,1,startOrder,-1), (host.config.autoStart.powerInfo,1,key,vm-XXX))

scala> val accumulator = Map[String, Map[String, Map[String, Any]]]()
accumulator: scala.collection.immutable.Map[String,Map[String,Map[String,Any]]] = Map()


scala> val result = tempList.foldLeft(accumulator) {
     |  case (acc, e) => { 
     |   val middleMap = acc.getOrElse(e._1, Map[String, Map[String, Any]]())
     |   val innerMap = middleMap.getOrElse(e._2, Map[String, Any]())
     |   acc + (e._1 -> (middleMap + (e._2 -> (innerMap + (e._3 -> e._4)))))
     | }}
result: scala.collection.immutable.Map[String,Map[String,Map[String,Any]]] = Map(host.config.autoStart.powerInfo -> Map(0 -> Map(key -> vm-YYY, startAction -> None, startOrder -> -1), 1 -> Map(startAction -> None, startOrder -> -1, key -> vm-XXX)))