loading...
Cover image for Get Your (Fizz)Buzz On

Get Your (Fizz)Buzz On

yechielk profile image Yechiel Kalmenson Updated on ・5 min read

FizzBuzz In 3 Acts

Learning to code was full of learning moments. One that I look back upon fondly was when I did the Flatiron lesson on FizzBuzz. That memory has been greatly reinforced when Flatiron hired me as a Technical Coach; FizzBuzz was one of my favorite labs to help new students with.

I will explain why the process of learning (and then teaching) FizzBuzz stood out so much, but first a word on what FizzBuzz is.

What The Fizz?

I know the first thing that comes to your mind when you hear FizzBuzz is probably something like this:
Fizzy Buzzy Was A Hare

FizzBuzz is a small game that interviewers use to weed out the extraordinarily bad coders from the ones who don’t know how to code at all. It’s a fairly simple problem, which anyone with the most rudimentary knowledge of how computers work should be able to solve, yet apparently, there are enough applicants for developer positions who can’t solve it to warrant its use in interviewing.

The problem is as follows:

Write a program that prints the numbers 1–100, but for every number that is a multiple of three print the word Fizz, for every number that’s a multiple of five print Buzz, and for every number that’s a multiple of both three and five print FizzBuzz. So the output for the first 15 numbers would look like this:
1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz…

In this post, I will be showing the solutions in Ruby, just because I like Ruby, and I think it’s the prettiest language. But most of the concepts can be ported to any language.

What Doesn’t Work

To explain the beauty of FizzBuzz, and why I love teaching it to new coders, let me demonstrate the first knee-jerk solution a new coder might come up with.

(1..100).each do |i|
    if i % 3 == 0
        puts "Fizz"
    elsif i % 5 == 0
        puts "Buzz"
    elsif i % 3 == 0 && i % 5 == 0
        puts "FizzBuzz"
    else
        puts i
    end
end

And in English:

For each number in the range of 1–100 check the following: if the number can be divided cleanly into three print Fizz, otherwise, if it can be divided cleanly into five print Buzz, otherwise, check if it can be divided cleanly into 3 AND 5 print FizzBuzz.

Seems pretty straightforward, no? If you gave those instructions to a human, you would be understandably annoyed if they messed it up. But apparently, that’s not clear enough for a computer. If you give the above code snippet to a computer, you would see a nice list of numbers, with plenty of Fizzes and Buzzes mixed in, but not one FizzBuzz. To understand why, we have to look at the difference between how humans look at instructions, and how computers do.

When a human looks at a block of code, we try to look at it as a whole entity. What is this code doing? What is it trying to accomplish? Why was it written? Computers don’t have that big-picture view; a computer will just analyze the code line by line and execute the instructions given.

Let’s try to look at the code above through the eyes of a computer.

First, the computer looks at the number 1. It takes it through the steps we outlined for it. Does it divide into 3? No. Okay, do nothing. Next, does it divide into 5? No. Okay, do nothing again. Next, does it divide into 3 and 5? No. Okay, do nothing. Next, print the number, got it.

The computer then repeats the process with number 2; it looks pretty much the same.

By number 3 the process is different. The computer tries dividing it into three; it works! Great! Let’s print Fizz. Next number, etc.

Now let’s take a look at what happens when we reach number 15. Remember, the computer only analyzes one line at a time, so the computer tries dividing 15 into 3, it works, the computer is happy, it prints Fizz and then goes right on to the next number, never reaching the line where its told to try dividing into 3 AND 5.

The Solution

Fortunately, this can be fixed by simply moving the last condition to the front, so that the computer will try to divide the number into 3 and five before it tries them separately, like this:

(1..100).each do |i|

  if i % 3 == 0 && i % 5 == 0
    puts "FizzBuzz"
  elsif i % 3 == 0
    puts "Fizz"
  elsif i % 5 == 0
    puts "Buzz"
  else
    puts i
  end
end

The More The Fuzzier

Now, as mentioned, FizzBuzz is a beginners problem, anyone who spent some time coding should be able to solve it without much thought. But in programming, there is never only one way to solve a problem.

All this talk of Fizz and Buzz is really giving me a lift

I would like to share a different way of solving FizzBuzz, one that looks a lot prettier in my opinion. This solution takes a slightly different approach:

(1..100).each do |i|

  output = ""
  output += "Fizz" if i % 3 == 0
  output += "Buzz" if i % 5 == 0
  output = i if output.empty?

  puts output
end

In English:

For each number in the range of 1–100 we start with an empty string (""), we then add "Fizz" to the string if the number is divisible by 3, we add "Buzz" to the string if the number is divisible by 5, if the string is still empty by this time (which will only happen if the number is not divisible by 3 or by 5) we will swap the empty string out for the number.

Notice how in this approach, we never check if the number is divisible by 3 AND 5, we just add Buzz to the existing string, which would be an empty string if the number is not divisible by three, and a string equaling Fizz if it is divisible by three.

But Does It Scale?

So now we solved the problem, but as programmers, we always try to improve.

Our solution works, the problem is it doesn’t scale really well. Suppose we wanted to do the same thing but for all the numbers between 1 and 50? 500? 5000? We would have to write a separate FizzBuzz program for each of those.

The solution would, of course, be, to write a FizzBuzz method that we can provide with a number, and have it run the FizzBuzz logic on every number from one through the number we provide. We can even give it a default argument so that if we don’t provide a number it will print FizzBuzz for 1–100.

That would look like this:

def fizzbuzz(num = 100)
  (1..num).each do |i|

    output = ""
    output += "Fizz" if i % 3 == 0
    output += "Buzz" if i % 5 == 0
    output = i if output.empty?

    puts output
  end
end

There are many more ways to solve FizzBuzz in Ruby (and in every other language), feel free to add your favorite in the comments.


This article has been cross-posted from my blog Coding Hassid.
You can read more about my coding journey there, or by following me on Twitter @yechielk

Posted on by:

yechielk profile

Yechiel Kalmenson

@yechielk

He/Him/His I'm a Software Engineer and a teacher. There's no feeling quite like the one you get when you watch someone's eyes light up learning something they didn't know.

Discussion

pic
Editor guide
 

Another one of the scalability aspects that we can explore is that what if the game wont stop at just 2 denominators (e.g. If I add 7 to the game, so for numbers multiple of 3 print Fizz, multiple of 5 print Buzz, multiple of 15 (3 and 5) print FizzBuzz, multiple of 35 (5 and 7) print BuzzBazz, multiple of 21 (3 and 7) print FizzBazz, and multiple of 105 (3 and 5 and 7) print FizzBuzzBazz). How we would go about scale it up on this aspect is to make use of hashmap, iterating through the map to determine the output. Here is the implementation in Go:

package main

import (
    "fmt"
    "sort"
    "strconv"
)

func scalableFizzBuzz(num int, denominatorsMap map[int]string) {
    // make a list of keys and sort it in order from small -> large
    // this is to make sure that it prints out "FizzBuzzBazz"
    // instead of random order like "BuzzFizzBazz" due to the
    // random nature of map iterator
    keys := make([]int, 0)
    for k := range denominatorsMap {
        keys = append(keys, k)
    }
    sort.Ints(keys)

    for i := 1; i <= num; i++ {
        output := ""
        for _, k := range keys {
            if i%k == 0 {
                output += denominatorsMap[k]
            }
        }
        if output == "" {
            output += strconv.Itoa(i)
        }
        output += ", "
        fmt.Print(output)
    }
}

func main() {
    scalableFizzBuzz(300, map[int]string{3: "Fizz", 5: "Buzz", 7: "Bazz"})
}
 

Here is the solution in js

function scalableFizzBuzz(num, denominatorsMap) {
  for (let i = 1; i <= num; i++) {
    output = "";
    Object.keys(denominatorsMap).forEach((k) => {
      if (i%k === 0) {
        output += denominatorsMap[k];
      }
    });
    if (output === "") {
      output += i;
    }
    console.log(output);
  }
}

scalableFizzBuzz(300, { 3: "Fizz", 5: "Buzz", 7: "Bazz" });
 

Nice, I never thought of scaling it in that direction.

I like the idea of using a Hash.

 

From what I gleaned from people who had used this test "in the wild", the single most neglected step was "or else, print the number." Pretenders (or not-paying-attention-to-details developers) would get so wrapped up in all of the exceptions that they'd forget the "else" condition at the end.

Just for fun, here's one you probably didn't expect... COBOL 85 or after. (imagine column 1 starts at column 8 if your compiler cares about that...)

edit: Holy cow, this code formatter knows COBOL! Disregard the note above...

       identification division.
         program-id. fizzbuzz.
       environment division.
       data division.
         working-storage section.
       77  nbr pic 9(3) value zero.
       77  quotient pic 9(3) value zero.
       77  rem pic 9(2) value zero.
       procedure division.
       begin.
           perform varying nbr from 1 by 1 until nbr > 100
               divide nbr by 15 giving quotient remainder rem
               evaluate rem
                   when 0
                       display "FizzBuzz"
                   when 3
                   when 6
                   when 9
                   when 12
                       display "Fizz"
                   when 5
                   when 10
                       display "Buzz"
                   when other
                       display nbr
               end-evaluate
           end-perform.
           stop run.

This outputs 002 for 2, but I'm not posting a completely correct FizzBuzz solution on the public Internet. Interviewers don't want memorizers, they want programmers. :)

 

Oh wow! I was NOT expecting a COBOL solution ;)

Guess that last part is left as an exercise for the reader (from my understanding, COBOL programmers don't have silly riddles in their interviews these days... :)

 

I'm less than 4 years from the end of my current employment, and need to decide what to do next. Helping prop up aging COBOL is on my list to consider. :)

To bring it into this century, here's an F# version...

let words =
  function
  | _ when 0 = nbr % 3 && 0 = nbr % 5 -> "FizzBuzz"
  | _ when 0 = nbr % 3 -> "Fizz"
  | _ when 0 = nbr % 5 -> "Buzz"
  | x -> string x
let fizzBuzz i =
  [1 .. i]
  |> List.map words
  |> String.concat ", "
fizzBuzz 100
|> System.Console.WriteLine

...although, technically, this separates them by commas rather than listing one per line.