The Mystery of the One-Line FizzBuzz

I’ve written FizzBuzz in Javascript a few times, but never in Ruby until today. My code was as follows:

We were printing numbers from 1 through 100 so I had the code loop 101 times, skipping the first number (which was 0), and then checking to see if numbers were divisible by 15, 3, and 5. If divisible by 3, I had it print “Fizz”, “Buzz”, or “FizzBuzz” for each of those. The first condition was if the number was divisible by 15, since all points at which 5 and 3 intersect are divisible by 15. This had to be the first condition in the if/else statement, otherwise “Fizz” or “Buzz” would have been written before “FizzBuzz” was even given a chance!

Now, I was pretty happy with this solution. I had a sense that of course it could be written better, more efficiently, more elegantly, but I wasn’t sure how and I felt that I did what I could with what I know. So when I found this solution to FizzBuzz I found it pretty exciting.

This code is a bit convoluted, but it makes sense if you break it down into pieces. To better explain it, I pulled apart the methods which gives a better idea of the steps involved.

The one-line FizzBuzz starts with puts, so we know it’s going to print out a number, Fizz, or Buzz for all the numbers between 1 and 100, since that is the range given. It uses the map method, which iterates through each number in a range and does something to transmute it in some way before returning it.

After establishing this, the one-line FizzBuzz evaluates the array [[“Fizz”][i % 3], [“Buzz”][i % 5]]. Let’s look at half of this to see what is going on. [“Fizz”][i % 3] can be thought of as array[i % 3]. That is, it is looking up the index in the array [“Fizz”]. However, since it is looking at a one-item array, anything other than index zero (i % 3 == 0) will return ‘nil’. When we do get to look at array[0] it will return “Fizz”. The same concept is used for [“Buzz”][i % 5]. Based on this, we know that anything divisible by 3 will return [[“Fizz”],nil], anything divisible by 5 will return [nil,[“Buzz”], and anything divisible by 15 will return [[“Fizz”],[“Buzz”]].

Okay, great. That’s the first hurdle. But we’re still a long way from a proper FizzBuzz solution. That’s when the compact and join methods come in to play. Each iteration of i, compact will strip all the nil values from the array, leaving us with [[“Fizz”]], [[“Buzz”]], [[“Fizz”],[“Buzz”]], and [ ] as the possible arrays. Join will then be used to combine “FizzBuzz” into one word when both are returned.

Finally, we check to see if the array was empty or not. If we’re left with an empty array, the number will be printed to the console. Otherwise, the contents of the array will be printed, based on which conditions were met.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>