2015-04-12 2 views
1

Я хотел бы объединить вложенные карты, но я не могу понять, как объединить внутренние карты.Scala inested map merge

var a = Map[String,Map[String,String]]() 
a = a + ("key1" -> Map("subkey1" -> "a")) 
a = a + ("key1" -> Map("subkey2" -> "b")) 
a = a + ("key2" -> Map("subkey1" -> "c")) 

Я хотел бы объединить все эти такие, что я получаю следующий результат:

Map("key1" -> Map("subkey1" -> "a", "subkey2" -> "b"), "key2" -> Map("subkey1" -> "c")) 

Есть ли стандартный метод для этого?

+1

Что делать, если есть конфликт между ключами в суб-карте? Как два 'subkey1' под картой' key1'. –

+0

@ m-z Идеально, что столкновение может быть выполнено с помощью функции 2-arity. В моем случае подпись будет больше похожа на Map [String, Map [String, Seq [String]]], а затем cons (добавить?) Значения вместе. – dannytoone

ответ

0

Нет ничего подходящего для этого встроенного, но getOrElse - ваш друг здесь. Ядро логики, если вы уверены, что нет подкарта коллекции, выглядит как

val x = a.getOrElse(key, mutable.Map.empty[String,String]) 
a = a + (key -> (x ++ subMap)) 

Если у Вас может быть столкновение, вам нужно сделать что-то другое, чем ++ --possibly использовать тот же трюк еще раз, чтобы получить подраздел и обновить значение, если оно существует.

0

Кажется, что для этого не существует прямого метода. Вы можете предоставить вспомогательный метод.

def mergeUpdate[K1, K2, V](base: Map[K1, Map[K2, V]], tuple: (K1, Map[K2, V])) = { 
    base + (tuple._1 -> (base.getOrElse(tuple._1, Map.empty) ++ tuple._2)) 
} 

затем переписать код:

var a = Map[String,Map[String,String]]() 
a = mergeUpdate(a, ("key1" -> Map("subkey1" -> "a"))) 
a = mergeUpdate(a, ("key1" -> Map("subkey2" -> "b"))) 
a = mergeUpdate(a, ("key2" -> Map("subkey1" -> "c"))) 

// => 
a: scala.collection.immutable.Map[String,Map[String,String]] = Map(key1 -> Map(subkey1 -> a, subkey2 -> b), key2 -> Map(subkey1 -> c)) 
1

Если это нормально использовать Scalaz - semigroups может помочь:

import scalaz._, Scalaz._ 
val map1 = Map("key1" -> Map("subkey1" -> "a")) 
val map2 = Map("key1" -> Map("subkey2" -> "b")) 
val map3 = Map("key2" -> Map("subkey1" -> "c")) 

scala> map1 |+| map2 |+| map3 
res0: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]] = 
    Map(key2 -> Map(subkey1 -> c), key1 -> Map(subkey2 -> b, subkey1 -> a)) 

Единственное ограничение - ваше значение должно быть Semigroup определено для того, чтобы столкновений с рукояткой:

trait A 
object A1 extends A 
object A2 extends A 

implicit val ASemigroup = new Semigroup[A] { 
    def append(a: A, b: => A) : A = a //"choose first" strategy 
} 

val map1 = Map("key1" -> Map("subkey1" -> (A1: A))) 
val map2 = Map("key1" -> Map("subkey1" -> (A2: A))) 

scala> map1 |+| map2 
res8: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,A]] = 
    Map(key1 -> Map(subkey1 -> [email protected])) 

Btw, строки уже имеют на них полугруппу, поэтому столкновение приведет к конкатенации строки там.

0

Если вы можете вытащить другую зависимость, вы можете попробовать это

scala> import com.daodecode.scalax.collection.extensions._ 
import com.daodecode.scalax.collection.extensions._ 

scala> val m1 = "key1" -> Map("subkey1" -> "a") 
m1: (String, scala.collection.immutable.Map[String,String]) = (key1,Map(subkey1 -> a)) 

scala> val m2 = "key1" -> Map("subkey2" -> "b") 
m2: (String, scala.collection.immutable.Map[String,String]) = (key1,Map(subkey2 -> b)) 

scala> val m3 = "key2" -> Map("subkey1" -> "c") 
m3: (String, scala.collection.immutable.Map[String,String]) = (key2,Map(subkey1 -> c)) 

scala> Seq(m1, m2, m3).toCompleteMap. 
    mapValues(_.foldLeft(Map.empty[String,String]){ 
    case (acc, m) => acc.mergedWith(m)(_ + _)}) 
res0: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]] = Map(key2 -> Map(subkey1 -> c), key1 -> Map(subkey1 -> a, subkey2 -> b)) 

toCompleteMap и mergedWith являются расширения методов из https://github.com/jozic/scalax-collection. Он опубликовал в Maven центральный

(_ + _) здесь ваша собственная функция разрешения столкновений