scala - funcion - Diferencia entre mapValues y transform en Map.
flatmap scal (3)
Aquí hay un par de diferencias no mencionadas:
mapValuescrea 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
mapValueses solo una vista, cada instancia contiene elMapreal, 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 unmapValuesen 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.