【问题标题】:Scala Map Transformation斯卡拉地图转换
【发布时间】:2013-02-25 05:00:24
【问题描述】:

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

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] 之间的数字并将其作为值的键

【问题讨论】:

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


    【解决方案1】:

    单行(长)解决方案:

    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}
     }
    

    【讨论】:

      【解决方案2】:

      编辑:在代码中添加了一些 cmets,以便更容易查看发生了什么

      从我的 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)))
      

      【讨论】:

      • 我现在看到我错过了 "host.config.autoStart.powerInfo" 应该是外部地图的关键的部分。要解决这个问题,只需在正则表达式 re 中添加另一个组,然后将 foldLeft 折叠在 Maps of Maps 的 Maps 上......你可能应该认真考虑另一个数据结构 :)
      • 感谢 Emil ... 出色的插图 .. 欣赏它 .... 根据您的建议,如果我应用另一个正则表达式分组来提取主键,即val re = """(.+)[(\d+)]\.(.+)""".r 您能否按照您的建议说明 tmpList 上的 foldLeft 部分。如果您可以通过更改来编辑代码,它真的会有所帮助......同意结构的混乱:)
      • @conikeec:如果答案对您有帮助,请点赞和/或接受。
      • @EmilH Emil ... 刚刚注意到输出与上面指定的所需输出不匹配。代码段中的累加器似乎有问题...
      • @conikeec 你是对的,定义 innerMap 的行有错字。更改它,使其返回预期结果。不过 Eastsun 提供的第二种解决方案更清洁。
      猜你喜欢
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 2011-08-10
      • 2018-12-11
      • 2011-09-16
      • 2016-01-31
      • 2017-03-17
      • 2017-10-23
      相关资源
      最近更新 更多