FizzBuzz is a simple kids game, often used as a test at programming interviews. It goes like this:
“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”.
Once you’ve realised that there’s a unique outcome for each permutation of the two conditions, the solution is pretty obvious. Let’s have a look at the truth table:
(n % 3 == 0) | (n % 5 == 0) | outcome |
---|---|---|
true | false | ‘Fizz’ |
false | true | ‘Buzz’ |
true | true | ‘FizzBuzz’ |
false | false | number |
We can express this as a pretty standard multi-conditional statement:
(1..100).each do |n|
if (n % 3 == 0) && (n % 5 != 0)
puts 'Fizz'
elsif (n % 3 != 0) && (n % 5 == 0)
puts 'Buzz'
elsif (n % 3 == 0) && (n % 5 == 0)
puts 'FizzBuzz'
else puts n
end
end
This will work fine, however I think we can do better than that. Now, remember we already saw how we can use a Hash to represent a truth table ? Well, this is a truth table right here so there’s nothing stopping us from using a Hash. Our clue is that the outcome of our table is a unique value (Fizz, Buzz, FizzBuzz or the given number), so this will be the key of our hash. We can now write a method like this one:
def fizz_buzz(n)
h = {
'Fizz' => (n % 3 == 0) && (n % 5 != 0),
'Buzz' => (n % 3 != 0) && (n % 5 == 0),
'FizzBuzz' => (n % 3 == 0) && (n % 5 == 0)
}
h.key(true) || n
end
First, we define a Hash whose values will evaluate to true or false depending on the number we pass into it. Now here’s the sweetness: since the conditions that are evaluated to produce each value are mutually exclusive, only a maximum of one of our Hash keys will have the value of ‘true’ for any given number. We then make sure we return this ‘true’ key (h.key(true)
) from our method. Of course if all our keys have the ‘false’ value (i.e. the passed number is neither divisible by 3, nor by 5) then h.key(true)
will evaluate to nil, so we use the logical OR operator to ensure that -in this case- we return the actual passed number.
Let’s try it out:
$> puts fizz_buzz(2)
=> 2
$> puts fizz_buzz(3)
=>Fizz
$> puts fizz_buzz(5)
=> Buzz
$> puts fizz_buzz(7)
=> 7
$> puts fizz_buzz(15)
=> FizzBuzz
Sweet! Now, to solve the original problem all we have to do is:
$>( 1..100).each {|num| puts fizz_buzz(num)}
Hash-tables in any language are a powerful construct. Hashes in Ruby though are truly awesome! They provide unrivalled versatility and expressiveness, just like most things Ruby. Use them often and enjoy them :)