immutable.Map的惯用“get or else update”?

时间:2010-12-08 09:34:43

标签: scala scala-collections

immutable.Map实例的getOrElseUpdate的惯用方法是什么?我使用下面的代码片段,但它似乎冗长而低效

var map = Map[Key, Value]()

def foo(key: Key) = {
  val value = map.getOrElse(key, new Value)
  map += key -> value
  value
}

4 个答案:

答案 0 :(得分:13)

我可能会实现这样的getOrElseUpdated方法:

def getOrElseUpdated[K, V](m: Map[K, V], key: K, op: => V): (Map[K, V], V) =
  m.get(key) match {
    case Some(value) => (m, value)
    case None => val newval = op; (m.updated(key, newval), newval)
  }
如果m具有key的映射或添加了映射key -> op的其他地图,则

返回原始地图。此方法的定义类似于getOrElseUpdate的{​​{1}}。

答案 1 :(得分:9)

让我总结一下你的问题:

  • 您想要在不可变数据结构上调用方法
  • 您希望它返回一些值重新分配var
  • 因为数据结构是不可变的,所以你需要
    • 返回一个新的不可变数据结构,或
    • 使用提供的闭包
    • 在方法内部进行赋值

所以,你的签名必须看起来像

def getOrElseUpdate(key: K): Tuple2[V, Map[K,V]]
//... use it like
val (v, m2) = getOrElseUpdate(k)
map = m2

def getOrElseUpdate(key: K, setter: (Map[K,V]) => Unit): V
//... use it like
val v = getOrElseUpdate(k, map = _)

如果您可以使用其中一种解决方案,您可以使用隐式转换添加自己的版本,但仅通过签名判断,我认为这些都不在标准库中。

答案 2 :(得分:8)

没有这样的方法 - 当您获得地图值时,地图变异(更新)是副作用(与编程的不变性/功能样式相矛盾)。

如果要使用默认值创建新的不可变映射,如果指定键的另一个值不存在,则可以执行以下操作:

map + (key -> map.getOrElse(key, new Value)) 

答案 3 :(得分:2)

如果您有不可变的地图,为什么不使用withDefaultwithDefaultValue