Putting the Pieces Together - rohgar/scala-principles-1 GitHub Wiki

Here we will see a larger example where we use the concepts we have learned so far.

Problem

Phone keys have mnemonics assigned to them.

val mnemonics = Map( '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", 
                     '6' -> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ")

Assume you are given a dictionary words as a list of words. Design a method:

translate(phoneNumber)

which produces all phrases of words that can serve as mnemonics for the phone number.

Example: The phone number 7225247386 should have the mnemonic Scala is fun as one element of the set of solution phrases.

Solution

package example

import scala.io.Source

object Phone {

  val in = Source.fromURL("https://raw.githubusercontent.com/rohitvg/scala-principles-1/master/resources/data/linuxwords.txt")

  // In the list of words, filter such that for each word, each character is a letter (since our map only consists of letters and no special characters.
  var words = in.getLines.toList.filter(word => word.forall(chr => chr.isLetter))

  val mnemonics = Map('2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", '6' -> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ")

  // Map each letter to its digit
  val charCode: Map[Char, Char] = for (
    (digit, letters) <- mnemonics;
    letter <- letters
  ) yield (letter -> digit)

  // Map a word to the digit string
  def wordCode(word: String): String = word.toUpperCase.map(charCode)

  // Map from digit string to respective possible words
  def numToWord: Map[String, Seq[String]] = {
    words.groupBy(wordCode) withDefaultValue (Seq()) // withDefaultValue (Seq()) is used so that if user tries to encode digits the words for which are not contained in our list, we do not get an exception.
  }

  // Function to encode a number as a list of all possible words
  def encode(numberStr: String): Set[List[String]] = {
    if (numberStr.isEmpty) Set(List())
    else {
      for {
        split <- 1 to numberStr.length
        word <- numToWord(numberStr.take(split))
        rest <- encode(numberStr.drop(split))
      } yield {
        word :: rest
      }
    }.toSet
  }

  // Test!
  encode("7225247386")

}