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
Difference between mapValues and transform in Map
提问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 isMap[_, _], but just try to send one across the wire).Since
mapValuesis just a view, every instance contains the realMap- which could be another result ofmapValues. Imagine you have an actor with some state, and every mutation of the state sets the new state to be amapValueson 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 ......是的,这两个都来自经验)。

