Map both keys and values of a Scala Map

Scala

Scala Problem Overview


Scala's MapLike trait has a method

mapValues [C] (f: (B) ⇒ C): Map[A, C] 

But I sometimes want a different type:

mapKeysAndValues [C] (f: (A, B) ⇒ C): Map[A, C] 

Is there a simple way to do this which I am missing? Of course, this can be done with a fold.

Scala Solutions


Solution 1 - Scala

map method iterates though all (key, value) pairs. You can use it like this:

val m = Map("a" -> 1, "b" -> 2)

val incM = m map {case (key, value) => (key, value + 1)}

Solution 2 - Scala

What about this code:

val m = Map(1 -> "one", 2 -> "two")
def f(k: Int, v: String) = k + "-" + v
m map {case (k, v) => (k, f(k, v))}

Which produces:

 Map(1 -> 1-one, 2 -> 2-two)

This can be packaged into utility method:

def mapKeysAndValues[A,B,C](input: Map[A,B], fun: (A, B) => C) = 
  input map {case(k,v) => (k, fun(k, v))}

Usage:

mapKeysAndValues(
  Map(1 -> "one", 2 -> "two"), 
  (k: Int, v: String) => k + "-" + v
)

Solution 3 - Scala

m map (t => (t._1, t._2 + 1))

m map (t => t._1 -> t._2 + 1)

Solution 4 - Scala

With some Scalaz:

scala> def fst[A, B] = (x: (A, B)) => x._1
fst: [A, B]=> (A, B) => A

scala> Map(1 -> "Lorem", 2 -> "Ipsum").map(fst &&& Function.tupled(_.toString + _))
res1: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> 1Lorem, 2 -> 2Ipsum)

I like @tenshi's solution better.

Solution 5 - Scala

You could create a utility class:

class MyMapLike[K,V](m:MapLike[K,V,_]){
 def mapKeysAndValues[R](f: (K, V) => R)={
   m.map{case (k,v)=> f(k,v)}
 } 
}
object MyMapLike{
 implicit def maplike2mymaplike[K,V](ml:MapLike[K,V,_]):MyMapLike[K,V]=new MyMapLike(m)

}

import MyMapLike._
Map(1 -> "one", 2 -> "two").mapKeysAndValues(k,v=>v*k)

Code not tested but it should work somehow simmilar like that.

Solution 6 - Scala

scala> val m = Map("a" -> 1, "b" -> 2)
val m: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)

// Convert to anther map
scala> m.map(kvp => (kvp._1, kvp._2 + 1))
val res1: scala.collection.immutable.Map[String,Int] = Map(a -> 2, b -> 3)

// Convert to a different Iterable type
scala> m.map(kvp => s"${kvp._1} -> ${kvp._2 + 1}")
val res2: scala.collection.immutable.Iterable[String] = List(a -> 2, b -> 3)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexey RomanovView Question on Stackoverflow
Solution 1 - ScalatenshiView Answer on Stackoverflow
Solution 2 - ScalaTomasz NurkiewiczView Answer on Stackoverflow
Solution 3 - ScalaGrigory KislinView Answer on Stackoverflow
Solution 4 - ScalamissingfaktorView Answer on Stackoverflow
Solution 5 - ScalaAlexView Answer on Stackoverflow
Solution 6 - ScalaGC001View Answer on Stackoverflow