David Zamora
David Zamora

Reputation: 413

Inverting a map in Scala

I'm doing a course in Coursera about Scala functional programming. I'm in the 6th week.

I have the following code:

/* define the map of numbers to letters */ 
val nmem = Map(
  '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", 
  '6' -> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ"
)

/* invert the map to get a map of letters to digits */
val charCode: Map[Char, Char] = 
  for {
       (digit, str) <- nmem
       ltr <- str
  } yield ltr -> digit

My question is how does the for-comprehension work? nmem introduces the key (char) and the value (string) into digit and str. And later we have: ltr <- str which I don't know how it works because I don't understand how the program knows that ltr is a char instead of an string.

Thank you in advance.

Upvotes: 1

Views: 89

Answers (3)

Andrey Tyukin
Andrey Tyukin

Reputation: 44908

This for-comprehension is desugared into

nmem.flatMap { case (digit, str) => str.map { ltr => (ltr, digit) } }

Since nmem has type Map[Char, String], the compiler knows that (digit, str) must be of type (Char, String). Thus, it knows that str is of type String. The elements of a String are of type Char, thus the type of ltr is inferred to be Char.

If you wanted to write down all the gory details of the type inference, you would get something like this:

nmem.flatMap[(Char, Char), Map[Char, Char]]{ 
  case (digit: Char, str: String) => 
  str.map[(Char, Char), Seq[(Char, Char)]]{ 
    (ltr: Char) => (ltr, digit) 
  } 
}

Fortunately, this is not necessary, because all those types can be inferred automatically.

Upvotes: 3

Randomness Slayer
Randomness Slayer

Reputation: 724

The syntax item <- collection is commonly used to iterate through each item in a collection.

A simple example would be:

for(mapping <- map){
   println(mapping)
}

In your case, this is essentially a nested for loop using yield syntax.

By default it will create a List and accumulate all the items.

Written with a bit more syntax may help:

val charCode : Map[Char,Char] = {  // Cast our result to a Map of (Char, Char)
    for ((digit, str) <- nmem;     // for every key-value pair (Char, String) in nmem
         ltr <- str)               // for every ltr (Char) in str (String)
    yield ltr -> digit             // add a new mapping to the map
}

You can check out https://docs.scala-lang.org/../for-comprehensions.html for more details

Upvotes: 0

Shankar Shastri
Shankar Shastri

Reputation: 1154

The first one actually (digit, str) <- nmem, gets one tuple from Map[String, String], and next one ltr <- str gets chars from that string.

Upvotes: -1

Related Questions