Let's Solve The FizzBuzz Challenge In Swift

Written by Reinder de Vries on October 9 2018 in App Development

Let's Solve The FizzBuzz Challenge In Swift

FizzBuzz is a legendary coding challenge. You simply must give it a try! But… what approaches can you use to solve FizzBuzz with the Swift programming language?

In this article, we’re going to solve the FizzBuzz challenge in three different ways:

  • With conditionals
  • With the switch statement
  • With .map()

Ready? Let’s go.

  1. What Is FizzBuzz?
  2. Solving FizzBuzz With Conditionals
  3. Solving FizzBuzz With Switch & Pattern Matching
  4. Solving FizzBuzz With Map()
  5. Further Reading

A while ago I did a live screencast, where I walk you through FizzBuzz. You can watch it here.

What Is FizzBuzz?

FizzBuzz is a coding challenge. Its instructions are:

  • Write a program that prints the numbers from 1 to 100
  • For numbers divisible by 3, print “Fizz”
  • For numbers divisible by 5, print “Buzz”
  • For numbers divisible by both 3 and 5, print “FizzBuzz”

The point of FizzBuzz is to test if a person knows how to code. It’s commonly used in coding interviews to test the problem-solving and coding skills of a candidate.

What’s so interesting about FizzBuzz is that its solution is counter-intuitive, and can’t be solved elegantly. This often confuses beginner programmers, which makes it an interesting challenge.

As you’ll see in the next section, FizzBuzz can’t be solved with a simple if-this-then-that approach. You’ll have to duplicate some of your code, which will make you second-guess your solution if you wanted to make your code as elegant as possible.

Let’s have a look then, shall we?

Fun Fact: No employer or client has ever asked me to solve FizzBuzz in a coding interview. They did ask me, however, to sort giraffes in groups of ascending heights. The differences in heights in a group couldn’t exceed 1, because that would make the giraffes insecure…

Solving FizzBuzz With Conditionals

We’re now going to write the most basic solution for FizzBuzz, step-by-step. The first step is of course, a for loop:

for i in 1...100 
{
    print(i)
}

The above for loop will loop over the range 1...100 and print out its individual numbers. So far so good!

The next step is to find out if a number is divisible by 3. Here’s how:

for i in 1...100
{
    if i % 3 == 0 {
        print("Fizz")
    } else {
        print(i)
    }
}

That results in the output:

1, 2, Fizz, 4, 5, Fizz, 7, 8, Fizz, 10, 11, Fizz

As expected, the numbers 3, 6, 9, 12, etc. are replaced by “Fizz”. Any other number is simply printed out as-is. So, how does that work?

The expression i % 3 == 0 uses the modulo operator % to find the remainder of a division. It divides i by 3 and sees if there’s something “left”. For instance, 5 divided by 3 has 2 remaining, i.e. 5 % 3 = 2. When the remainder is 0 you know for certain that i is divisible by 3.

The result of the i % 3 == 0 expression is a boolean, so you can use it in an if-statement (also called a conditional). When the expression is true, “Fizz” is printed. When it’s false, the else block is executed and the number i is printed.

Now, let’s extend the code to also test for divisibility by 5. Like this:

for i in 1...100
{
    if i % 3 == 0 {
        print("Fizz")
    } else if i % 5 == 0 {
        print("Buzz")
    } else {
        print(i)
    }
}

Its output is:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11

As expected, the numbers 5 and 10 are replaced with “Buzz”. The else if block checks that i % 5 == 0 is true, and prints out “Buzz”.

Why doesn’t it print “FizzBuzz” too at this point? Because the if, else if and else blocks are evaluated one by one, from top to bottom. When one expression is true, the expressions below it aren’t executed. So, when i is divisible by 3, the first block executes, and the other block are not.

So… how can you incorporate “FizzBuzz” at this point? That’s what the whole challenge is about! You have two options:

  1. You add another if i % 5 == 0 conditional inside the first i % 3 conditional. After all, you’re checking that i is divisible by both 3 and 5.
  2. You add a top-level if i % 3 == 0 && i % 5 == 0 to the code. This way you’re evaluating the value i twice.

Let’s look at the first approach. It goes like this:

for i in 1...100
{
    if i % 3 == 0 {
        if i % 5 == 0 {
            print("FizzBuzz")
        } else {
            print("Fizz")    
        }
    } else if i % 5 == 0 {
        print("Buzz")
    } else {
        print(i)
    }
}

Do you see that nested if-statement inside the first i % 3 == 0 block? It works like this:

  • Check if i is divisible by 3, and if that’s true:
    • Check if i is divisible by 5, and if that’s true, print “FizzBuzz”
    • If that’s not true, in else, print “Fizz”
  • (The other conditionals still work the same.)

This code is pretty hard to read. You can’t immediately assess the behavior of every conditional, and you can’t shake the inelegance of executing i % 5 twice.

Can we use a different approach? Yes! Have a look:

for i in 1...100
{
    if i % 3 == 0 && i % 5 == 0 {
        print("FizzBuzz")
    } else if i % 3 == 0 {
        print("Fizz")
    } else if i % 5 == 0 {
        print("Buzz")
    } else {
        print(i)
    }
}

Much better, right? We’re still executing some code twice, but at least it’s readable. You can see at a glance that we’re checking if i is divisible by both 3 and 5, or just by one of them, or else.

However, this solution still executes both i % 3 == 0 and i % 5 == 0 twice, at worst. The code first evaluates i % 3 == 0 && i % 5 == 0, and then those divisions individually.

A most efficient value of i here is 15, for example, because that hits the first conditional immediately. A most inefficient value is one you can’t divide by 3 or 5, so you have to execute every conditional before ending up at else.

Become a professional  iOS developer

Get started with iOS 12 and Swift 5

Sign up for our iOS development course Zero to App Store to learn iOS development with Swift 5, and start with your professional iOS career.

Solving FizzBuzz With Switch & Pattern Matching

The Swift programming language has a very cool feature called pattern matching. We can use it with the switch statement to match its different values with different clauses.

Let’s have a look:

for i in 1...100
{
    switch (i % 3 == 0, i % 5 == 0)
    {
    case (true, false):
        print("Fizz")
    case (false, true):
        print("Buzz")
    case (true, true):
        print("FizzBuzz")
    default:
        print(i)
    }
}

The code is similar to what we had before. We’re looping over 1...100 and printing “Fizz”, “Buzz”, “FizzBuzz” or a number for every iteration of the loop.

Instead of an if statement, we’re using switch. In short, a switch statement takes one expression, and has a number of case blocks for every possible value of that expression.

In the above code, we’re constructing a tuple out of the expression (i % 3 == 0, i % 5 == 0). A tuple combines two values in an ordered list. Because both values in the tuple can be true or false, the entire tuple now has 4 different values:

(true, true)
(false, false)
(true, false)
(false, true)

In the switch statement we can now match those tuples to different case blocks. Here, walk through this list on your own:

  • (true, false) means that i is only divisible by 3
  • (false, true) means that i is only divisible by 5
  • (true, true) means that i is divisible by both 3 and 5
  • (false, false) means that i isn’t divisible by neither 3 nor 5

In code, that looks like this:

switch (i % 3 == 0, i % 5 == 0)
{
case (true, false):
    print("Fizz")
case (false, true):
    print("Buzz")
case (true, true):
    print("FizzBuzz")
default:
    print(i)
}

See how the expressions i % 3 == 0 and i % 5 == 0 are assessed, and its values matched to different case blocks? The default block matches anything that the other blocks don’t match.

And you know what’s so cool about the above code? The (i % 3 == 0, i % 5 == 0) expression is evaluated once for every iteration of i. Unlike the previous example, with the if statements, the code that evaluates if i is divisible only runs once. Albeit for every iteration of i, but that’s still better than twice for every iteration of i.

The switch statement in Swift has no implicit fall-through, unlike other programming languages. You won’t have to explicitly break a case. When you want a case to fall-through, use fallthrough explicitly.

Solving FizzBuzz With Map()

The previous examples all printed out values to the Console, but what if you want to evaluate a range of FizzBuzz as a whole?

Let’s spice up FizzBuzz! Just because we can. It’s about playing with code, alright?

First, we’re going to put FizzBuzz into a closure. Like this:

let fizzbuzz:(Int) -> String = { i in
    switch (i % 3 == 0, i % 5 == 0)
    {
    case (true, false):
        return "Fizz"
    case (false, true):
        return "Buzz"
    case (true, true):
        return "FizzBuzz"
    default:
        return "\(i)"
    }
}

The code is similar to what you’ve seen before. Instead right now, we can call fizzbuzz() for any arbitrary value and get the right string back.

fizzbuzz(15)
// Output: FizzBuzz

fizzbuzz(3)
// Output: Fizz

And then here’s a beautiful one-liner:

Array(1...100).map(fizzbuzz).joined(separator: ", ")

Whaaat? How’s it work? It’s simple:

  • Create an array with integer values from 1 to 100
  • Call map(_:) on that array, calling the closure fizzbuzz for every item in the array, mapping integer values to string values
  • Calling joined(separator:) on the resulting array of strings, effectively glueing them together with commas.

Its result:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, ... FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz

Awesome!

Become a professional  iOS developer

Get started with iOS 12 and Swift 5

Sign up for our iOS development course Zero to App Store to learn iOS development with Swift 5, and start with your professional iOS career.

Further Reading

FizzBuzz is a terrific primer for coding interview challenges. It helps you to think lateraly instead of intuitively, and to assess every different scenario and edge case that can occur in your code. And it’s a whole lot of fun!

Want to learn more? Check out these resources:

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.