Blog

Front End Development topics with a touch of humor

FizzBuzz

Get out of the wet paper bag!

October 8, 2020


Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.

What's the deal with FizzBuzz? What does it have to do with wet paper bags? And why should this ordinary-looking word problem concern you?

To find out, read on!

"You'd probably think they're a good developer if you'd never seen them write code"

The magnificiently named Imran Ghory is responsible for the above quote and the FizzBuzz challenge. According to his blog, he created this as a test for possible new hires as a way to filter out the weak programmers who, and I paraphrase, couldn't code their way out of a wet paper bag.

Must...escape...bag...through programming!

Apparently, the majority of CS grads can't solve this task--I hesitate to call it an "algorithm" because the word seems too dignified, and even senior programmers might take up to a quarter of an hour.

Marijin Haverbeke, of Eloquent JavaScript fame, writes in his book that this is a common interview question.

It sounds to me, then, that this ranks right up there with asynchronous programming and the mastery of this as far as topics a JavaScript coder should know. So let's get to it!

            function fizzBuzz(n) {
                const result = [];
                for (let i = 1; i <= n; i ++) {
                    if (i % 5 === 0 && i % 3 === 0) {
                       result.push("FizzBuzz");
                    } else if (i % 5 === 0) {
                        result.push("Buzz");
                    } else if (i % 3 === 0) {
                        result.push("Fizz");
                    } else 
                      result.push(i)
                   }
                return result;
            }   
            console.log(fizzBuzz(100));
          

So here is my solution: am I hired? It only took me 14 minutes and 45 seconds!

Okay, not to humble brag, but it took more like five minutes. But after I wrote it, tested it, fixed the inevitable bug (sad face), I went out into the internet and looked at other solutions and... well, spoiler--other people came up with way cooler implementations! Maybe we'll go look at some of those, but first, let's check mine out.

The task asks for the program to count to 100, so you could just write out the code, but I couldn't help myself and made it a function. A function takes a couple more lines of code, because you need to wrap the stuff in the brackets, but you get the ability to easily change the arguments--what if I wanted to only FizzBuzz up to 20 for testing purposes and didn't want to see 100 different entries every time?

Imran Ghory writes, "After a fair bit of trial and error I’ve come to discover that people who struggle to code don’t just struggle on big problems, or even smallish problems (i.e. write a implementation of a linked list). They struggle with tiny problems."

There is the ring of truth here, but I see it from the opposite side. I have found that for me, the best way to attack a problem is to break it down into its smallest possible constituents. We can even do that with FizzBuzz.

What is FizzBuzz really asking?

In a way, it's like four separate programs:

              1)
              for (let i = 1; i <= 100; i++) {
                  console.log(i);
              }
              2) 
              for (let i = 0; i <= 100; i++) {
                  if (i % 3 === 0) {
                      console.log("Fizz")
                  }
              }
              3) 
              for (let i = 0; i <=100; i++) {
                  if (i % 5 === 0) {
                      console.log("Buzz")
                  }
              }
              4) 
              for (let i = 0; i <= 100; i++) {
                  if (i % 5 === 0 && i % 3 === 0) {
                      console.log("FizzBuzz")
                  }
              }
          

Not too bad. We have the for loop that counts from 1 to 100, inclusive. We print the number as it increments.

In the later variations, we check the number using a control statement using the handy remainder operator, % (apparently this is called the modulo operator in other languages but JavaScript is special). The way this works is, if the result of using the % on a value is 0, that means it's evenly divisible.

In 4), we test for both conditions and thus capture the outcome of being divisible by both 3 and 5.

These are all pretty basic programming concepts, but we're not done yet. First, you may have noticed in my original program that I pushed the output into an array called "result." Again, this is not strictly necessary, but it's nicer to have the results stored in a variable than just spewed out onto the console where you'll never see it again or be able to use it.

The second thing is that there is trick to combining the three variations here. And the trick has to do with the computer-y nature of computers.

One step at a time

I've often remarked in these pages that computers love to go to an element, process it, and then go to the next element, and process that, and just keep going down the list. Computers are very linear.

Humans, on the other hand, are holistic and intuitive. A computer just does what you tell it to... a human sees an error message and thinks someone Up Above has got it out for him.

What I'm getting at is that order can matter here. Check out an implementation where order could trip us up.

            function badBuzz(n) {
                const result = [];
                for (let i = 1; i <= n; i ++) {
                    if (i % 3 === 0) {
                        result.push("Fizz");
                        continue;
                    }
                    if (i % 5 === 0 && i % 3 === 0) {
                       result.push("FizzBuzz");
                       continue;
                    } 
                    //other stuff
                    } 
                    result.push(i)
                   }
                return result;
            }   
           

This function tests for 3 and outputs the desired "Fizz" if it evaluates for true. If so, the continue statement jumps back to the next iteration.

Then it checks for 3 and 5 and pushes out the "FizzBuzz" if that is true. And then jumps.

On first blush, that makes sense, but there is a problem here. We need these outcomes to be exclusive. 15 is divisible by 3 and 5. If we leave this as is, 15 will print for two numbers. We only want it to print for the second.

We could solve this simply by switching up the order of the program.

            function betterBuzz(n) {
                const result = [];
                for (let i = 1; i <= n; i ++) {
                    if (i % 5 === 0 && i % 3 === 0) {
                        result.push("FizzBuzz");
                        continue;
                     } 
                    if (i % 3 === 0) {
                        result.push("Fizz");
                        continue;
                    }
                    //other stuff
                    } 
                    result.push(i)
                   }
                return result;
            }   
           

This would solve that issue. It tests for 15 first. If that is satisfied, we're good and we jump to the next iteration. If not, we go down and see if 3 works. We can then add the 5 condition. If that doesn't work, we'll finally just let the function print i.

Now, you may have noticed something a bit artificial here. I used the continue keyword, which causes a jump. This isn't really the most idiomatic way to write the function. We have an else keyword which accomplishes the same thing in a more readable and idiomatic way. But I thought the point was worth making.

Well, hopefully this discussion has been useful, and we are all better prepared for wet paper bags and silly programming questions!