9

I have a map where the key is a String and I need to change every key to lower case before work with this map.

How can I do it in Scala? I was thinking something like:

var newMap = scala.collection.mutable.Map[String, String]()
data.foreach(d => newMap +=(d._1.toLowerCase -> d._2))   

What is the best approach for it? Thanks in advance.

Jonik
  • 80,077
  • 70
  • 264
  • 372

2 Answers2

9

The problem here is that you're trying to add the lower-cased keys to the mutable Map, which is just going to pile additional keys into it. It would be better to just use a strict map here, rather than a side-effecting function.

val data = scala.collection.mutable.Map[String, String]("A" -> "1", "Bb" -> "aaa")
val newData = data.map { case (key, value) => key.toLowerCase -> value }

If you really want to do it in a mutable way, then you have to remove the old keys.

data.foreach { case (key, value) =>
    data -= key
    data += key.toLowerCase -> value
}

scala> data
res79: scala.collection.mutable.Map[String,String] = Map(bb -> aaa, a -> 1)
Régis Jean-Gilles
  • 32,541
  • 5
  • 83
  • 97
Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
  • 2
    Doing it the mutable way as you show is a bit dodgy because you are modifying the map as you are iterating it. Effectively this means that foreach's body can be executed several times (you can easily verify it by adding a log). In this particular case this does not affect the result because converting to lowercase is idempotent, but that's not a good habit to have and will break for any non idempotent operation. – Régis Jean-Gilles Mar 31 '15 at 14:08
  • Good point. I prefer to avoid the mutable map entirely (clearly it could have bitten me). – Michael Zajac Mar 31 '15 at 14:10
  • 1
    BTW you can shorten the code slightly by using `transform` instead: `data.transform{ (key, _) => key.toLowerCase }` – Régis Jean-Gilles Mar 31 '15 at 14:16
4

Your approach would work, but in general in Scala for this kind of transformation the immutable variants of the collections are preferred.

You can use the map method of the Map class with the following one liner:

val m = Map("a"->"A", "B"->"b1", "b"->"B2", "C"->"c")
m.map(e=>(e._1.toLowerCase,e._2))
Gregor Raýman
  • 3,051
  • 13
  • 19