2014-09-27 133 views
1

我正在嘗試編寫通用方法來合併集合地圖集合。這是一口,但假設你有幾個結果來自groupBy,你想通過鍵連接。合併集合地圖集合的通用方法

這裏就是我想要寫:

def mergeMaps[A, B <: Iterable[_]](maps: Seq[Map[A, B]]): Map[A, B] = maps.reduce { (leftMap, rightMap) => 
    (leftMap.toList ++ rightMap.toList).groupBy(_._1).map { case (k, v) => 
    k -> v.map(_._2).reduce(_ ++ _) 
    } 
} 

目前,我得到這個錯誤:

<console>:9: error: Cannot construct a collection of type That with elements of type Any based on a collection of type Repr. 
      k -> v.map(_._2).reduce(_ ++ _) 
            ^

我認爲這具有與CanBuildFrom魔不符合我的reduce什麼jiving做。我該如何做這項工作?

回答

1

你只是不需要存在類型:

def mergeMaps[A, B](maps: Seq[Map[A, Iterable[B]]]) = 
    maps.map(_.toList).reduce(_ ++ _).groupBy(_._1).mapValues(_.map(_._2).flatten) 


scala> mergeMaps(Seq(Map("a" -> List(1,2), "b" -> List(1)), Map("a" -> List(3)))) 
res20: scala.collection.immutable.Map[String,List[Int]] = 
     Map(b -> List(1), a -> List(1, 2, 3)) 
+0

美麗。這基本上是我要去的。 – acjay 2014-09-27 13:27:44

1

不減少的樣子:

scala> val m1 = List("a"->1,"b"->2).groupBy(_._1) 
m1: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(b -> List((b,2)), a -> List((a,1))) 

scala> val m2 = List("a"->3,"b"->4).groupBy(_._1) 
m2: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(b -> List((b,4)), a -> List((a,3))) 

scala> m1 map { case (k,v) => (k, v ++ m2(k)) } 
res0: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(b -> List((b,2), (b,4)), a -> List((a,1), (a,3))) 

或可能!(m2 contains k)

scala> m1 map { case (k,v) => (k, (m2 get k) map (v ++ _) getOrElse v) } 
res1: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(b -> List((b,2), (b,4)), a -> List((a,1), (a,3))) 

反之亦然:

scala> val m2 = List("a"->3,"b"->4,"c"->5).groupBy(_._1) 
m2: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(b -> List((b,4)), a -> List((a,3)), c -> List((c,5))) 

scala> type M = Map[String,List[(String, Int)]] 
defined type alias M 

scala> def r(m1: M, m2: M) = (m1.keySet ++ m2.keySet).toList map (k => (k, m1.getOrElse(k,Nil) ++ m2.getOrElse(k,Nil))) toMap 
warning: there was one feature warning; re-run with -feature for details 
r: (m1: M, m2: M)scala.collection.immutable.Map[String,List[(String, Int)]] 

scala> r(m1,m2) 
res4: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(b -> List((b,2), (b,4)), a -> List((a,1), (a,3)), c -> List((c,5)))