scala - funcion - Diferencia entre mapValues y transform en Map.
flatmap scal (3)
Aquí hay un par de diferencias no mencionadas:
mapValues
crea un Mapa que NO es serializable, sin ninguna indicación de que sea solo una vista (el tipo esMap[_, _]
, pero solo intenta enviar uno a través del cable).Como
mapValues
es solo una vista, cada instancia contiene elMap
real, que podría ser otro resultado demapValues
. Imagina que tienes un actor con cierto estado, y cada mutación del estado establece que el nuevo estado sea unmapValues
en el estado anterior ... al final tienes mapas profundamente anidados con una copia de cada estado anterior del actor (y , sí, ambos son de experiencia).
En Scala Map
(ver API ), ¿cuál es la diferencia en semántica y rendimiento entre mapValues
y transform
?
Para cualquier mapa dado, por ejemplo
val m = Map( "a" -> 2, "b" -> 3 )
ambos
m.mapValues(_ * 5)
m.transform( (k,v) => v * 5 )
Entregar el mismo resultado.
Digamos que tenemos un Map[A,B]
. Para aclarar: siempre me refiero a un Map
inmutable.
mapValues
toma una función B => C
, donde C
es el nuevo tipo para los valores.
transform
toma una función (A, B) => C
, donde esta C
es también el tipo para los valores.
Así que ambos resultarán en un Map[A,C]
.
Sin embargo, con la función de transform
puede influir en el resultado de los nuevos valores por el valor de sus claves.
Por ejemplo:
val m = Map( "a" -> 2, "b" -> 3 )
m.transform((key, value) => key + value) //Map[String, String](a -> a2, b -> b3)
Hacer esto con mapValues
será bastante difícil.
La siguiente diferencia es que la transform
es estricta, mientras que mapValues
le dará solo una vista, que no almacenará los elementos actualizados. Se parece a esto:
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)
}
(tomado de https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244 )
Por lo tanto, el rendimiento depende de lo que sea más efectivo. Si f
es costoso y solo accede a algunos elementos del mapa resultante, mapValues
podría ser mejor, ya que f
solo se aplica a pedido. De lo contrario me atendría a map
o transform
.
transform
también se puede expresar con el map
. Supongamos que m: Map[A,B]
y f: (A,B) => C
, luego
m.transform(f)
es equivalente a m.map{case (a, b) => (a, f(a, b))}
collection.Map
no proporciona transform
: tiene una firma diferente para los mapas mutables e inmutables.
$ 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
La transformable mutable muta en su lugar:
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)
Así que la transformación mutable no cambia el tipo de mapa:
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)
... como puede suceder al construir un nuevo mapa.