有没有办法让Scala HashMap自动初始化值?'

时间:2011-09-22 06:47:46

标签: scala

我认为可以按照以下方式完成

val hash = new HashMap[String, ListBuffer[Int]].withDefaultValue(ListBuffer())
hash("A").append(1)
hash("B").append(2)
println(hash("B").head)

然而,上面打印出不直观的值1.我想要

hash("B").append(2)

在幕后执行以下操作

if (!hash.contains("B")) hash.put("B", ListBuffer())

2 个答案:

答案 0 :(得分:10)

使用getOrElseUpdate在访问点提供默认值:

scala> import collection.mutable._
import collection.mutable._

scala> def defaultValue = ListBuffer[Int]()
defaultValue: scala.collection.mutable.ListBuffer[Int]

scala> val hash = new HashMap[String, ListBuffer[Int]]
hash: scala.collection.mutable.HashMap[String,scala.collection.mutable.ListBuffer[Int]] = Map()

scala> hash.getOrElseUpdate("A", defaultValue).append(1)

scala> hash.getOrElseUpdate("B", defaultValue).append(2)

scala> println(hash("B").head)
2

答案 1 :(得分:8)

withDefaultValue每次都使用完全相同的值。在您的情况下,每个人都可以使用相同的空ListBuffer

如果您使用withDefault,则每次都可以生成新的ListBuffer,但不会存储。

所以你真正喜欢的是一种可以添加默认值的方法。您可以在包装类中创建这样的方法,然后编写隐式转换:

class InstantiateDefaults[A,B](h: collection.mutable.Map[A,B]) {
  def retrieve(a: A) = h.getOrElseUpdate(a, h(a))
}
implicit def hash_can_instantiate[A,B](h: collection.mutable.Map[A,B]) = {
  new InstantiateDefaults(h)
}

现在你的代码按照需要工作了(除了额外的方法名称,如果你愿意,可以选择更短的方法名称):

val hash = new collection.mutable.HashMap[
  String, collection.mutable.ListBuffer[Int]
].withDefault(_ => collection.mutable.ListBuffer())

scala> hash.retrieve("A").append(1)

scala> hash.retrieve("B").append(2)

scala> hash("B").head
res28: Int = 2

请注意,解决方案(带隐式)根本不需要知道默认值本身,因此您可以执行此操作一次,然后默认添加内容。