2013-03-09 3 views
1

Может кто-то порекомендовать функциональный способ преобразовать карту, указанную ниже отScala Карта Преобразование

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. Extract, что перед подстрочный и сделать что ключ
  2. Извлеките число между индексом [x] и сделайте, чтобы ключ значения

ответ

3

A (длинный) раствор одна строка:

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

Fabulous .. @Eastsum – conikeec

2

Edit: добавлены некоторые комментарии к коду, чтобы сделать его легче увидеть, что происходит на

скопированного из моего РЕПЛ:

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' fold over Map of Maps of Maps ... Возможно, вам стоит серьезно подумать о другой структуре данных :) :) –

+0

Спасибо Emil ... Отличная иллюстрация. Оцените это .... Исходя из вашего предложения, если я применил другую группу регулярных выражений, чтобы извлечь главный ключ, т. Е. вал ре = "" "(. +) \ [(\ D +) \] \. (. +)" "". Г Можете ли вы показать часть foldLeft на tmpList как вы советовали. Если вы можете отредактировать код с изменениями, это может реально помочь ... Согласитесь с беспорядочностью структуры :) – conikeec

+0

@conikeec Done :) –

Смежные вопросы