Scala algorithm: 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.
Algorithm in Scala
13 lines of Scala (compatible versions 2.13 & 3.0), 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")
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.
Def Inside Def
A great aspect of Scala is being able to declare functions inside functions, making it possible to reduce repetition.
It is also frequently used in combination with Tail Recursion.
Pattern Matching
Pattern matching in Scala lets you quickly identify what you are looking for in a data, and also extract it.