scal funcion example scala dictionary scala-collections

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 es Map[_, _] , pero solo intenta enviar uno a través del cable).

  • Como mapValues es solo una vista, cada instancia contiene el Map real, que podría ser otro resultado de mapValues . Imagina que tienes un actor con cierto estado, y cada mutación del estado establece que el nuevo estado sea un mapValues 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.