FizzBuzz

Apparently this is a test that is used in interviews to distinguish the real programmers from all the others who have applied for the job. As one page I looked at about this test put it - The Fizz-Buzz test is an interview question designed to help filter out the 99.5% of programming job candidates who can't seem to program their way out of a wet paper bag.

So just what is this test?

"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'."

Now there are a number of ways to approach this particular problem and while all of the different approaches work there is a significant difference between the different approaches that makes one approach far superior to the alternatives. By seeing who selects which approach to solving this problem you can distinguish the good programmers from the rest. Of course the response you get will also depend on how you present the question.

The first time I came across this problem the question wasn't quite the one shown above. Instead what the question asked for was a function that would return the appropriate FizzBuzz value for a supplied number and to write the code in such a way that the function would fit inside a tweet - ie. in 140 characters or less. Now with the question worded that way the emphasis is on keeping the code short. I therefore wrote the shortest version of the function that is possible given that it had to contain both the keyword 'function' and the specific function name 'fizzbuzz'. My solution was therefore 76 characters meaning that I used just over half of the available space for the solution. This is NOT the way I would have coded an answer to the question if the space requirement had not been the most prominent part of the question I saw.

function fizzbuzz(n){return (n%3)?((n%5)?n:'Buzz'):(n%5)?'Fizz':'FizzBuzz';}

As the shortest solution to one part of the problem this answer could be considered the 'best' solution if best is defined as meaning the shortest possible solution to that specific problem. It certainly isn't the approach you'd take to solving a real world problem unless space for the code really was at such a premium as to require using as few characters as possible.

Let's look at why this solution is inappropriate once space considerations are eliminated from consideration. The code is almost completely unreadable. It has three ternary operators nested inside one another to provide the four possible outcomes.

Rewriting the code to use if statements would be an improvement as at least it would be more readable

if (n%3) {
if (n%5) return n;
else return 'Buzz';
} else {
if (n%5) return 'Fizz';
else return 'FizzBuzz';
}

This is slightly more readable but it still isn't obvious just how you get this from the original question as the if tests are all backwards from what the question is asking for in order to produce the desired result as n%3 is true when n is not divisible by three and similarly for n%5.

Switching the tests around a different way has them produce a better match to the wording of the question.

if(!(n%3) && !(n%5)) return 'FizzBuzz';
if(!(n%3)) return 'Fizz';
if(!(n%5)) return 'Buzz';
return n;

Now this solution plugged into the function would just fit within the 140 characters and is far more readable than either of the above shorter variants - always assuming that the person knows that !(n%3) is true when n is divisible by 3 - and so on. The problem is that unless you need the shortest possible code (in which case you'd go with my first solution) this is completely the wrong approach to take in solving the problem. If it were the appropriate approach to take then the following looks slightly tidier as it reduces each if statement to a single test (since any number divisible by both 3 and 5 is divisible by 15).

if(!(n%15)) return 'FizzBuzz';
if(!(n%5)) return 'Buzz';
if(!(n%3)) return 'Fizz';
return n;

That it isn't the appropriate way to solve the problem becomes obvious if we add another condition to the criteria. Let's add that multiples of seven should print 'Bazz' and that should also be added to the end where the numbers are divisible by 3, 5 or 15. Expanding our latest solution to include this extra condition means adding tests for every possible combination as follows:

if(!(n%105)) return 'FizzBuzzBazz';
if(!(n%35)) return 'BuzzBazz';
if(!(n%21)) return 'FizzBazz';
if(!(n%15)) return 'FizzBuzz';
if(!(n%7)) return 'Bazz';
if(!(n%5)) return 'Buzz';
if(!(n%3)) return 'Fizz';
return n;

Our three if statements has become seven if statements just to handle one extra condition added to the original criteria. Add another condition and we'd need fifteen if statements. This approach is extremely unfriendly to any changes required to the criteria.

A completely different approach to the problem produces a far more flexible solution to the problem which when you add the extra criteria as we did above clearly demonstrates how much easier it is to modify when the criteria changes. The following code does exactly the same thing as the version immediately above but it does it with four if statements (counting the ternary in the return as the fourth) instead of seven.

t='';
if(!(n%3))t+='Fizz';
if(!(n%5))t+='Buzz';
if(!(n%7))t+='Bazz';
return(t.length>0?t:n);

This version only needs to test each of the original values and takes care of the combinations automatically. For the original criteria our function is only a dozen or so characters longer than the shortest version that I started with and even with the extra criteria added in we only need 110 characters for the function so it would still fit inside a tweet if we were using that as part of our criteria. In fact once you get to three conditions this is the only variant that would fit inside a tweet and you could possibly even fit five conditions this way without exceeding the 140 characters.

function fizzbuzz(n){t='';if(!(n%3))t+='Fizz';if(!(ni%5))t+='Buzz';return(t.length>0?t:n);}

The other obvious thing with this approach is readability. This variant is not only easier to extend but it is also far more readable even when compressed than the original version. The only reason I didn't give this as my reply to the 'fizzbuzz in a tweet' question is that I was looking for the shortest answer.

Of course if we return to the original question then all we need to do is to set up a loop to call the function for the required range of numbers.

 

This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow
Donate