Scala从列表中连接映射

时间:2015-07-10 13:07:40

标签: scala dictionary fold

拥有val mapList: List[Map[String, Int]],我想做类似的事情:

val map = mapList foldLeft (Map[String, Int]()) ( _ ++ _ )

val map = mapList foldLeft (Map[String, Int]())
 ( (m1: Map[String, Int], m2: Map[String, Int]) => m1 ++ m2 )

这两个选项都没有编译(首先说“扩展函数(x, y) => x ++ y缺少参数类型”,第二个说“类型不匹配;找到(Map[String, Int], Map[String, Int]) => Map[String, Int];所需:String”。

我想要实现连接不可变地图列表的经典解决方案,例如List( Map("apple" -> 5, "pear" -> 7), Map("pear" -> 3, "apricot" -> 0) )会产生Map("apple" -> 5, "pear" -> 10, "apricot" -> 0)

使用scala 2.10.5

1 个答案:

答案 0 :(得分:3)

您需要在foldLeft之前添加一个点。在特殊条件下,您只能使用空格而不是点,例如对于具有1个参数(arity-1方法)的方法:

val map = mapList.foldLeft(Map[String, Int]()) ( _ ++ _ )

您可以阅读有关方法调用最佳做法的更多信息here

您可能也对reduce方法感兴趣,这些方法是fold方法的专用版本,其中返回类型与集合元素的类型相同。例如,reduceLeft使用集合的第一个元素作为foldLeft的种子。当然,由于这依赖于第一个元素的存在,如果集合为空,它将抛出异常。由于reduceLeft只接受1个参数,因此您可以更轻松地使用空格来调用该方法:

mapList.reduceLeft( _ ++ _)
mapList reduceLeft(_ ++ _)

最后,你应该注意到你在这里所做的只是合并地图。使用++合并地图时,您只需覆盖地图中已存在的键 - 您将不会添加重复键的值。如果您想这样做,可以按照here提供的答案,将其应用到foldLeftreduceLeft。例如:

mapList reduceLeft { (acc, next) => 
    (acc.toList ++ next.toList).groupBy(_._1).toMap.mapValues(_.map(_._2).sum) 
}

或略有不同:

mapList.map(_.toSeq).reduceLeft(_ ++ _).groupBy(_._1).toMap.mapValues(_.map(_._2).sum)

而且,如果您正在使用Scalaz,那么最简洁:

mapList reduceLeft { _ |+| _ }