1

我一直在用可变地图计算出现次数:

var bar = collection.mutable.Map[Int, Int]().withDefaultValue(0)

现在bar(a) += b工作得很好,无论密钥a是否bar已经存在(在这种情况下,它将被添加)。

我用可变映射的可变映射尝试了同样的事情:

var foo = collection.mutable.Map[Int, collection.mutable.Map[Int, Int]]().
          withDefaultValue(collection.mutable.Map().withDefaultValue(0))

foo(a)(b) += x没有语法糖怎么看?

使用Scala 中的所有语法糖实例是什么?我假设它扩展到:

foo.apply(a).put(b, foo.apply(a).apply(b) + x)

但是,为什么这不会foo像介绍性示例中那样相应地更新自身(即,如果之前不存在key,foo则不会有专用的 key 值)?a

编辑:正如Perseids 指出的那样foo(a)(b) += x将更改可变的默认值。这是一个理想的功能吗?按照DaoWengetOrElseUpdate的建议使用似乎是克服这两个问题的最佳方法。但是,虽然这对于 type 的函数很有效,但对于 type 的函数Int => Int => Int来说确实很麻烦Int => Int => Int => Int => Int。所以我仍然很高兴有任何建议!

4

2 回答 2

3

这实际上是 的问题withDefaultValue,而不是+=操作员的问题。如果给定键不存在,您的第一个withDefaultValuefor返回一个新的可变映射。foo当您进行查找foo(a)(b)时,如果foo(a)不存在,则返回一个新地图,我们将其称为tmpfoo(a)(b) += x然后基本上扩展为:

val tmp = foo(a)
tmp(b) += x

问题是 onlytmp正在更新+=,而不是foo. 因此,您的更新发生在 上tmp,但tmp在通话后被丢弃,因为它从未存储在任何地方。

如果您希望您的父地图得到更新,您可能需要考虑使用getOrElseUpdate而不是依赖withDefaultValue.


注意:正如 Perseids 在下面的评论中指出的那样,withDefaultValue采用按值参数。这意味着每次您从地图中获取未设置的键时,它都会返回相同的可变地图实例!getOrElseUpdate这是您应该考虑使用(使用按名称参数)或至少withDefault使用函数的另一个原因(这一切都假设您实际上希望地图中的每个插槽都有不同的地图实例......)

于 2013-10-09T00:08:29.327 回答
1

foo(a)(b) += x没有语法糖怎么看?

这取决于返回的对象是否foo(a)(b)具有命名的方法+=。如果是这样,那么它相当于:

foo.apply(a).apply(b).+=(x)

如果没有,那么它相当于:

foo.apply(a).update(b, foo.apply(a).apply(b).+(x))

foo.apply(a)除非没有(我认为)的重复评估。

于 2013-10-09T10:21:05.567 回答