Iterating over a map is slightly more complex than over other collections, because a Map is the combination of 2 collections. The keys and the values.

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

m.keys    // = Iterable[Int] = Set(1, 2)
m.values  // = Iterable[String] = MapLike("a", "b")

We make a Map using tuples. -> is just syntactic sugar for making a tuple.

val x = 1 -> 2                                     //  = (Int, Int) = (1,2)
val y = (1, 2)                                     //  = (Int, Int) = (1,2)
x == y                                             //  = Boolean = true
Map((1, "a"), (2, "b")) == Map(1 -> "a", 2 -> "b") //  = Boolean = true

We get these tuples when we iterate over a Map.

m.foreach { a: (Int, String) =>
  println(s"$a")
}

prints

(1,a)
(2,b)

To get the key and the value we could use _1 and _2

m.foreach { a: (Int, String) =>
  val key = a._1
  val value = a._2
  println(s"key:$key value:$value")
}

But this looks confusing. It's better to unpack it using case.

m.foreach { case (k, v) =>
  println(s"key:$k value:$v")
}

We can use map to change the keys of a Map.

m.map { case (k, v) =>
    k + 1 -> v
}
// = Map[Int,String] = Map(2 -> "a", 3 -> "b")

If we just want to change the values, it's better to use mapValues.

m.mapValues { v => v + v }
// = Map[Int,String] = Map(1 -> "aa", 2 -> "bb")

And of course our favorite method, flatMap, also works on Maps.

m.flatMap { case (k, v) =>
  Map(k -> v, k + 10 -> v)
}
// = Map[Int,String] = Map(1 -> "a", 11 -> "a", 2 -> "b", 12 -> "b")
shadow-left