61

刚才我很惊讶地得知这mapValues会产生一个视图。结果如下例所示:

case class thing(id: Int)
val rand = new java.util.Random
val distribution = Map(thing(0) -> 0.5, thing(1) -> 0.5)
val perturbed = distribution mapValues { _ + 0.1 * rand.nextGaussian }
val sumProbs = perturbed.map{_._2}.sum
val newDistribution = perturbed mapValues { _ / sumProbs }

这个想法是我有一个分布,它受到一些随机性的干扰,然后我重新规范化它。代码实际上在其初衷中失败了:因为mapValues产生 a view_ + 0.1 * rand.nextGaussian总是在使用时重新评估perturbed

我现在正在做类似distribution map { case (s, p) => (s, p + 0.1 * rand.nextGaussian) }的事情,但这有点冗长。所以这个问题的目的是:

  1. 提醒不知道这一事实的人。
  2. 寻找他们制作mapValuesoutputview的原因。
  3. 是否有生产混凝土的替代方法Map
  4. 有没有其他常用的收集方法有这个陷阱。

谢谢。

4

3 回答 3

40

有一张关于此的票,SI-4776(由 YT 提供)。

介绍它的提交有这样的说法:

根据 jrudolph 的建议,制作filterKeysmapValues 转换抽象地图,并为不可变地图复制功能。从不可变地图移动transformfilterNot通用地图。法勒审查。

我无法找到 jrudolph 的原始建议,但我认为这样做是为了mapValues提高效率。提出问题,这可能会让您感到惊讶,但如果您不太可能多次迭代这些值,mapValues 则效率会更高。

作为一种变通方法,可以mapValues(...).view.force生成一个新的Map.

于 2013-02-14T20:10:04.923 回答
11

scala 文档说:

key将每个地图映射到的地图视图f(this(key))。生成的地图包装原始地图而不复制任何元素。

所以这应该是意料之中的,但这让我很害怕,我明天必须审查一堆代码。我没想到会有这样的行为:-(

只是另一种解决方法:

您可以调用toSeq以获取副本,如果需要将其返回 map toMap,但这不必要的创建对象,并且对使用有性能影响map

可以相对容易地编写,mapValues不创建视图,我明天会做,如果没有人在我之前做,我会在这里发布代码;)

编辑:

我找到了一种“强制”视图的简单方法,在 mapValues 之后使用“.map(identity)”(因此无需实现特定功能):

scala> val xs = Map("a" -> 1, "b" -> 2)
xs: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1, b -> 2)

scala> val ys = xs.mapValues(_ + Random.nextInt).map(identity)
ys: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1315230132, b -> 1614948101)

scala> ys
res7: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1315230132, b -> 1614948101)

很遗憾,返回的类型实际上不是视图!否则一个人本来可以称之为“力量”......

于 2013-02-14T19:53:33.757 回答
0

在 scala 2.13 中更好(并且已弃用),现在返回 MapView: API Doc

于 2019-11-11T15:45:25.567 回答