在 scala.immutable.Map 中更新多个值的惯用方法

Posted

技术标签:

【中文标题】在 scala.immutable.Map 中更新多个值的惯用方法【英文标题】:Idiomatic way to update multiple values in scala.immutable.Map 【发布时间】:2014-03-26 18:02:47 【问题描述】:

我需要更新(检索和增加)绑定到映射中两个键的两个不同值。这两个键有时会重合。 我现在有以下代码:

// val map: Map[Int, Int]
// val key1, key2: Int
if (key1 == key2) 
  tailRecFunction(someArg, map 
    + Tuple2(key1, 2 + map.getOrElse(key1, 0)))
 else 
  tailRecFunction(someArg, map 
    + Tuple2(key1, 1 + map.getOrElse(key1, 0))
    + Tuple2(key2, 1 + map.getOrElse(key2, 0)))

如你所见,如果你在key1 == key2 时使用else 块,那么key1 == key2 的值将错误地增加1 而不是2 --- 第二个元组错误地更新原始值,而不是第一个元组应用的值。有没有更简洁的写法?

【问题讨论】:

为什么会被否决?请说明原因,以便我知道我在哪里犯了错误! 这个问题应该链接到Idiomatic way to update value in a Map based on previous value 【参考方案1】:

首先,您可以简化映射以在不存在键时返回0

val map0 = Map.empty[Int, Int] withDefaultValue 0

那么您可以放心地调用map(key) 而不是map.getOrElse(key, 0)

其次,您可以使用箭头关联语法来创建Tuple2 实例。 IE。 key -> value 而不是 Tuple2(key, value)

第三,我根本不会介绍if ... then ... else。只需连续更新每个键的映射:

def addKey(map: Map[Int, Int], key: Int) = map + (key -> (map(key) + 1))

val map1 = addKey(map0, key1)
val map2 = addKey(map1, key2)
tailRecFunction(someArg, map2)

【讨论】:

谢谢,很好的建议! (Ad3):我仍然可以避免使用 val newMap = addKey(addKey(oldMap, key1), key2) 进行 val 定义 我强烈建议不要以这种方式使用withDefaultValue,尤其是对于不可变映射。这是 scala 集合库中的缺陷之一。请参阅编译器开发人员groups.google.com/forum/#!topic/scala-internals/R4fTU_5XVZs/… 之间的这场辩论。例如,gist.github.com/drstevens/9201268 @drstevens 在直方图和计数元素的情况下,withDefaultValue(0) 是非常明智的 IMO,但是是的,您在转换地图时应该小心。 另一个SO answer 建议使用ScalaZ 库中的~ 运算符,这样可以避免withDefaultValue 的危险。【参考方案2】:

另一个SO Answer 建议使用 Map (ScalaZ) 的 Monoid 特性:

tailRecFunction(someArg, map |+| Map(key1 -> 1) |+| Map(key2 -> 1))

|+| 运算符将对属于同一键的值求和。

【讨论】:

原理与Best way to merge two maps and sum the values of same key?类似

以上是关于在 scala.immutable.Map 中更新多个值的惯用方法的主要内容,如果未能解决你的问题,请参考以下文章

在 PostgreSQL 中更新行时更新时间戳

在 CoreData 中更新项目后,项目不会在 UI 中更新

我们可以在 mongodb 中更新/更新记录吗?数据源是kafka

离子v3在应用程序中进行制造和更新,以更新它在数据库中而不是在应用程序中正在更新的数据

使用 upsert 更新:true 是否在 express 中更新,猫鼬?

部分更新在过程中不起作用