Diciamo che abbiamo un Map[A,B]
. Per chiarimenti: mi riferisco sempre a un Map
immutabile.
mapValues
prende una funzione B => C
, dove C
è il nuovo tipo per i valori.
transform
prende una funzione (A, B) => C
, dove questo C
è anche il tipo per i valori.
Quindi entrambi si traducono in un Map[A,C]
.
Tuttavia con la funzione transform
è possibile influenzare il risultato dei nuovi valori in base al valore delle proprie chiavi.
Ad esempio:
val m = Map("a" -> 2, "b" -> 3)
m.transform((key, value) => key + value) //Map[String, String](a -> a2, b -> b3)
Fare questo con mapValues
sarà molto difficile.
La prossima differenza è che transform
è rigoroso, mentre mapValues
fornirà solo una vista, che non memorizzerà gli elementi aggiornati. Ecco come si presenta:
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)
}
(tratto da https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244)
Così prestazioni-saggio dipende da cosa è più efficace. Se f
è costoso e si accede solo a pochi elementi della mappa risultante, mapValues
potrebbe essere migliore, poiché f
viene applicato solo su richiesta. In caso contrario, attenersi a map
o transform
.
transform
può anche essere espresso con map
. Assumere m: Map[A,B]
e f: (A,B) => C
, quindi
m.transform(f)
è equivalente a m.map{case (a, b) => (a, f(a, b))}