Difference between mapValues and transform in Map

Let’s say we have a Map[A,B]. For clarification: I’m always referring to an immutable Map.

mapValues takes a function B => C, where C is the new type for the values.

transform takes a function (A, B) => C, where this C is also the type for the values.

So both will result in a Map[A,C].

However with the transform function you can influence the result of the new values by the value of their keys.

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 mapValues will be quite hard.

The next difference is that transform is strict, whereas mapValues will give you only a view, which will not store the updated elements. It looks like this:

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)

So performance-wise it depends what is more effective. If f is expensive and you only access a few elements of the resulting map, mapValues might be better, since f is only applied on demand. Otherwise I would stick to map or transform.

transform can also be expressed with map. Assume m: Map[A,B] and f: (A,B) => C, then

m.transform(f) is equivalent to m.map{case (a, b) => (a, f(a, b))}

Leave a Comment