【问题标题】:Generic method to merge a collection of maps of collections合并集合映射集合的通用方法
【发布时间】:2014-11-22 03:23:09
【问题描述】:

我正在尝试编写通用方法来合并集合映射的集合。这是一口,但假设您有多个来自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 或其他东西有关。我怎样才能做到这一点?

【问题讨论】:

    标签: scala collections scala-collections


    【解决方案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))
    

    【讨论】:

    • 美丽。这基本上就是我想要的。
    【解决方案2】:

    reduce 看起来不像:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 2010-10-19
      相关资源
      最近更新 更多