Let's Solve The FizzBuzz Challenge in Swift

Written by Reinder de Vries on August 5 2020 in App Development, Swift

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:

  1. With conditionals
  2. With the switch statement
  3. With .map()

Ready? Let’s go.

  1. What is FizzBuzz?
  2. Solving FizzBuzz with Conditionals
  3. Solving FizzBuzz with Switch and 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 or efficiently. 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… I’ve included a few brain-tickling coding challenges at the end of this tutorial.

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.

Instead of the modulo operator %, you can also use i.isMultiple(of: 3) in Swift. This is clearer but more verbose.

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 do 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, like 7, so you have to execute every conditional before ending up at else.

Get hired as an iOS developer

Learn to build iOS 14 apps with Swift 5

Sign up for my iOS development course, and learn how to start your career as a professional iOS developer.

Solving FizzBuzz with Switch and 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 switch cases.

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 full 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? Note that the default block matches anything that the other blocks don’t match.

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.

Note: 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.

Just for fun, let’s look at another way of solving FizzBuzz that’s identical to the one with switch, but syntactically different. Check this out:

let FIZZ = true
let BUZZ = true

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

What’s going on here? We’ve changed a few things:

  • At the top of the code we’ve defined constants FIZZ and BUZZ, both set to true. They’re going to serve as “aliases” for the Fizz, Buzz and FizzBuzz numbers in the range from 1 to 100.
  • Instead of pattern matching with true and false, we’re now using the constants (“aliases”) FIZZ and BUZZ for true in case. We’ve changed false in an underscore _, so we’re ignoring those false values.
  • The order of cases in switch has changed. We’ll need to make sure that the pattern for FizzBuzz matches first. If we hadn’t, the “Fizz” case would also match for “FizzBuzz” because we’re ignoring the false value matches.

Even though the way the code works is still the same, it’s syntactically different. We’re using the FIZZ and BUZZ constants to obscure the pattern matching in case, which makes the code more expressive. Neat!

Big thanks for this approach to Tim “Mr. C” Colson.

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, right?

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 does it work? It’s simple:

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

The 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!

Get hired as an iOS developer

Learn to build iOS 14 apps with Swift 5

Sign up for my iOS development course, and learn how to start your career as a professional iOS developer.

Further Reading

FizzBuzz is a terrific primer for coding interview challenges. It helps you to think strategically 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!

Looking for more fun Swift challenges? Check these out:

Want to learn more? Check out these resources:

Reinder de Vries

Hi, I'm Reinder.
I help developers play with code.

Get the Weekly

Get iOS/Swift tutorials and insights in your inbox, every Monday.
  • This field is for validation purposes and should be left unchanged.

Most Popular

Browse Topics

Swift Sandbox

Code Swift right in your browser!
Go to the Swift Sandbox

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.

×

Start your iOS career
Learn how in my free 7-day course

  • This field is for validation purposes and should be left unchanged.

No spam, ever. Unsubscribe anytime. Privacy Policy