Fizz Buzz in purely functional immutable Scala

Algorithm goal

FizzBuzz is one of the most general and common programming questions, and tells about programming skills the most. It is ubiquitous.

It challenges notions of how to deal with combining output types, working in terms of expressions versus statements, and also parametrisation versus hard-coding.

This problem is particularly suited for Scala as it permits many different styles of programming - so even if you have the produced the expected result, it does not mean that you have the most idiomatic code. Often, in other programming languages, it is in fact more convenient and effective to write code in a more mutable style.

The problem statement is: for every number, you should be able to output 'Fizz' if it is divisible by 3, 'Buzz', if it is divisible by 5, 'FizzBuzz' if it is divisible by 3 * 5 (so that the words are combined), and in all other cases such as '14', return '14', the original number.

Explanation

Firstly, we declare a mapping from number to a word. This immediately separates you away from classes of other programmers, who would proceed to hard-code numbers 3 and 5 in the logic of the 'fizzBuzz' function itself.

With Scala's 'collect' method, you can do a 'filter' and a 'map' operation in one go, saving on typing. Here, we collect all the numbers with their corresponding words, and get a List as output. If there are no words that were discovered in the candidate checking process, this means that we must return the original number; otherwise, we return the combination of words (this is © from www.scala-algorithms.com)

Scala Concepts & Hints

Collect

'collect' allows you to use Pattern Matching, to filter and map items.

assert("Hello World".collect {
  case character if Character.isUpperCase(character) => character.toLower
} == "hw")

Read more

Pattern Matching

Pattern matching in Scala lets you quickly identify what you are looking for in a data, and also extract it.

assert("Hello World".collect {
  case character if Character.isUpperCase(character) => character.toLower
} == "hw")

Read more

Def Inside Def

A great aspect of Scala is being able to declare functions inside functions, making it possible to reduce repetition.

def exampleDef(input: String): String = {
  def surroundInputWith(char: Char): String = s"$char$input$char"
  surroundInputWith('-')
}

Algorithm in Scala

13 lines of Scala (version 2.13), showing how concise Scala can be!

val NumToString = List(3 -> "Fizz", 5 -> "Buzz")

def fizzBuzz(n: Int): String = {
  def isDivisibleBy(i: Int): Boolean = n % i == 0
  NumToString.collect({
    case (n, str) if isDivisibleBy(n) => str
  }) match {
    case Nil =>
      s"$n"
    case strings =>
      strings.mkString
  }
}

Test cases in Scala

assert(fizzBuzz(1) == "1")
assert(fizzBuzz(2) == "2")
assert(fizzBuzz(3) == "Fizz")
assert(fizzBuzz(5) == "Buzz")
assert(fizzBuzz(12) == "Fizz")
assert(fizzBuzz(13) == "13")
assert(fizzBuzz(15) == "FizzBuzz")
def fizzBuzz(n: Int): String = ???