【问题标题】:Scala concatenate maps from a listScala 连接列表中的映射
【发布时间】:2015-07-10 13:07:40
【问题描述】:

拥有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

【问题讨论】:

    标签: scala dictionary fold


    【解决方案1】:

    您需要在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 { _ |+| _ }
    

    【讨论】:

    • 您可以将它用于 arity-1 方法或 arity-0 方法(尽管通常不鼓励使用后者)。您不能将其用于具有多个参数或多个参数列表的方法。
    • 使用 scalaz 更简洁:mapList.suml.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多