2013-03-09 186 views
1

可有人建議從斯卡拉地圖轉型

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

一個行(長)解決方案:

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

很棒.. @Eastsum – conikeec 2013-03-10 07:21:36

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))) 
+0

我現在看到我錯過了「host.config.autoStart.powerInfo」本應該是外部映射關鍵的部分。爲了解決這個問題,只需將另一個組添加到regex're'中,然後在地圖貼圖上摺疊'foldLeft'即可......但您應該認真考慮另一個數據結構:) – 2013-03-09 19:22:53

+0

感謝Emil ...出色的插圖。 。欣賞它.... 根據你的建議,如果我申請另一個正則表達式分組來提取主鍵,即 VAL重= 「」 「(+)\ [(\ d +)\] \。(+)」, 「」 的。R 可以請說明上tmpList的foldLeft部等你建議。如果你可以好心地編輯代碼的變化,它可以真正幫助... 同意結構的混亂:) – conikeec 2013-03-09 19:51:59

+0

@conikeec完成:) – 2013-03-09 20:32:02