scala Map中mapValues和transform的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25635803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 06:32:21  来源:igfitidea点击:

Difference between mapValues and transform in Map

scaladictionaryscala-collections

提问by elm

In Scala Map(see API) what is the difference in semantics and performance between mapValuesand transform?

在斯卡拉Map(见API)是什么样的语义表现之间的差异,mapValues以及transform

For any given map, for instance

例如,对于任何给定的地图

val m = Map( "a" -> 2, "b" -> 3 )

both

两个都

m.mapValues(_ * 5)
m.transform( (k,v) => v * 5 )

deliver the same result.

提供相同的结果。

回答by Kigyo

Let's say we have a Map[A,B]. For clarification: I'm always referring to an immutable Map.

假设我们有一个Map[A,B]. 澄清一下:我总是指一个不可变的Map.

mapValuestakes a function B => C, where Cis the new type for the values.

mapValues接受一个函数B => C,其中C是值的新类型。

transformtakes a function (A, B) => C, where this Cis also the type for the values.

transform接受一个函数(A, B) => C,其中这C也是值的类型。

So both will result in a Map[A,C].

所以两者都会产生一个Map[A,C].

However with the transformfunction you can influence the result of the new values by the value of their keys.

但是,使用该transform函数,您可以通过键的值影响新值的结果。

For example:

例如:

val m = Map( "a" -> 2, "b" -> 3 )
m.transform((key, value) => key + value) //Map[String, String](a -> a2, b -> b3)

Doing this with mapValueswill be quite hard.

这样做mapValues会非常困难。

The next difference is that transformis strict, whereas mapValueswill give you only a view, which will not store the updated elements. It looks like this:

下一个区别是transform严格的,而mapValues只会给你一个视图,它不会存储更新的元素。它看起来像这样:

protected class MappedValues[C](f: B => C) extends AbstractMap[A, C] with DefaultMap[A, C] {
  override def foreach[D](g: ((A, C)) => D): Unit = for ((k, v) <- self) g((k, f(v)))
  def iterator = for ((k, v) <- self.iterator) yield (k, f(v))
  override def size = self.size
  override def contains(key: A) = self.contains(key)
  def get(key: A) = self.get(key).map(f)
}

(taken from https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244)

(取自https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244

So performance-wise it depends what is more effective. If fis expensive and you only access a few elements of the resulting map, mapValuesmight be better, since fis only applied on demand. Otherwise I would stick to mapor transform.

因此,在性能方面,这取决于什么更有效。如果f很昂贵并且您只访问结果地图的几个元素,mapValues可能会更好,因为f仅按需应用。否则我会坚持使用mapor transform

transformcan also be expressed with map. Assume m: Map[A,B]and f: (A,B) => C, then

transform也可以用 表示map。假设m: Map[A,B]f: (A,B) => C,那么

m.transform(f)is equivalent to m.map{case (a, b) => (a, f(a, b))}

m.transform(f)相当于 m.map{case (a, b) => (a, f(a, b))}

回答by som-snytt

collection.Mapdoesn't provide transform: it has a different signature for mutable and immutable Maps.

collection.Map不提供transform:它对可变和不可变 Map 具有不同的签名。

$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val im = Map('a -> 1, 'b -> 2, 'c -> 3)
im: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 1, 'b -> 2, 'c -> 3)

scala> im.mapValues(_ * 7) eq im
res0: Boolean = false

scala> im.transform { case (k,v) => v*7 } eq im
res2: Boolean = false

scala> val mm = collection.mutable.Map('a -> 1, 'b -> 2, 'c -> 3)
mm: scala.collection.mutable.Map[Symbol,Int] = Map('b -> 2, 'a -> 1, 'c -> 3)

scala> mm.mapValues(_ * 7) eq mm
res3: Boolean = false

scala> mm.transform { case (k,v) => v*7 } eq mm
res5: Boolean = true

Mutable transform mutates in place:

可变变换就地变异:

scala> mm.transform { case (k,v) => v*7 }
res6: mm.type = Map('b -> 98, 'a -> 49, 'c -> 147)

scala> mm.transform { case (k,v) => v*7 }
res7: mm.type = Map('b -> 686, 'a -> 343, 'c -> 1029)

So mutable transform doesn't change the type of the map:

所以可变变换不会改变地图的类型:

scala> im mapValues (_ => "hi")
res12: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi)

scala> mm mapValues (_ => "hi")
res13: scala.collection.Map[Symbol,String] = Map('b -> hi, 'a -> hi, 'c -> hi)

scala> mm.transform { case (k,v) => "hi" }
<console>:9: error: type mismatch;
 found   : String("hi")
 required: Int
              mm.transform { case (k,v) => "hi" }
                                           ^

scala> im.transform { case (k,v) => "hi" }
res15: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi)

...as can happen when constructing a new map.

...构建新地图时可能会发生这种情况。

回答by codingismy11to7

Here's a couple of unmentioned differences:

以下是一些未提及的差异:

  • mapValuescreates a Map that is NOT serializable, without any indication that it's just a view (the type is Map[_, _], but just try to send one across the wire).

  • Since mapValuesis just a view, every instance contains the real Map- which could be another result of mapValues. Imagine you have an actor with some state, and every mutation of the state sets the new state to be a mapValueson the previous state...in the end you have deeply nested maps with a copy of each previous state of the actor (and, yes, both of these are from experience).

  • mapValues创建一个不可序列化的 Map,没有任何迹象表明它只是一个视图(类型是Map[_, _],但只是尝试通过线路发送一个)。

  • 由于mapValues只是一个视图,每个实例都包含真实的Map-这可能是mapValues. 想象一下,你有一个具有某种状态的角色,并且状态的每个变化都将新状态设置为mapValues前一个状态的 a ......是的,这两个都来自经验)。