Scala 连接列表中的地图

Scala concatenate maps from a list

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

两个选项都未编译(第一个说 "missing parameter type for expanded function (x, y) => x ++ y",第二个说 "type mismatch; found (Map[String, Int], Map[String, Int]) => Map[String, Int]; required: String")。

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

使用 Scala 2.10.5

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

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

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

您可能还对 reduce 方法感兴趣,它们是 fold 方法的特殊版本,其中 return 类型与集合。例如 reduceLeft 使用集合的第一个元素作为 foldLeft 的种子。当然,由于这依赖于第一个元素的存在,如果集合为空,它会抛出异常。由于 reduceLeft 只接受 1 个参数,您可以更轻松地使用 space 来调用方法:

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 { _ |+| _ }