mutable.Map deep merge
Есть ли в Scala краткий способ глубокого слияния двух изменяемых карт?
case class K1(i: Int)
case class K2(i: Int)
def deepMerge(map: mutable.Map[K1, Map[K2, List[Int]]],
mergee: mutable.Map[K1, Map[K2, List[Int]]]
): Unit = ???
Примеры:
Я.
val map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(1) -> Map(K2(1) -> List(2)))
deepMerge(map, mergee)
map = mutable.Map(K1(1) -> Map(K2(1) -> List(1, 2)))
II.
val map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(1) -> Map(K2(2) -> List(1)))
deepMerge(map, mergee)
map = mutable.Map(K1(1) -> Map(K2(1) -> List(1), K2(2) -> List(1)))
III.
val map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(2) -> Map(K2(2) -> List(1)))
deepMerge(map, mergee)
map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)), K1(2) -> Map(K2(2) -> List(1)))
Т.е. если на обеих картах представлен один и тот же ключ, то значения, которым ключи соответствуют ( List[Int]), объединяются.
Есть ли способ реализовать это кратко, избегая множества проверок, представлен ли конкретный ключ или нет на другой карте? Также можно использовать библиотеки FP, такие как scalaz или cats.
Ответы
Я добавляю еще один ответ, используя кошек.
То, что вы описываете, на самом деле является поведением кошек . Таким образом, вы можете просто использовать |+|оператор comb ( ) для глубокого слияния карт:
import cats.implicits._
import cats._
case class K1(i: Int)
case class K2(i: Int)
val map = Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = Map(K1(1) -> Map(K2(1) -> List(2)))
val deepMerged = map |+| mergee
println(deepMerged) // HashMap(K1(1) -> HashMap(K2(1) -> List(1, 2)))
Проблема в том, что в Cats lib нет экземпляра Semigroup для mutable.Map, но вы можете получить его из одного для неизменяемого:
import cats.implicits._
import scala.collection.immutable
import scala.collection.mutable
import cats._
//here I derivive Semigroup instance for mutable.Map from instance for immutable.Map
implicit def mutableMapSemigroup[K, V: Semigroup]: Semigroup[mutable.Map[K, V]] = Semigroup[immutable.Map[K, V]].imap(c => mutable.Map.from(c))(c => immutable.Map.from(c))
case class K1(i: Int)
case class K2(i: Int)
val map = mutable.Map(K1(1) -> mutable.Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(1) -> mutable.Map(K2(1) -> List(2)))
println(map |+| mergee)
Но имейте в виду, что это фактически преобразует изменяемую карту в неизменяемую, затем выполняет слияние, а затем преобразует обратно в изменяемую карту, поэтому, вероятно, это не очень эффективно.
Это могло бы сработать.
def deepMerge(mergeA: Map[K1, Map[K2, List[Int]]],
mergeB: Map[K1, Map[K2, List[Int]]]
): Map[K1,Map[K2,List[Int]]] =
(mergeA.toList ++ mergeB.toList).groupMap(_._1)(_._2).map{
case (k1,ms) =>
k1 -> ms.flatMap(_.toList).groupMap(_._1)(_._2).map{
case (k2,ls) => k2 -> ls.flatten
}
}
Я не тестировал его с mutableКартами, но он должен работать примерно так же.