The shortest FizzBuzzBazz - can you do better?

3 Dec 2012 - George Zahariev

FizzBuzz is very simple problem, and as such its concise solutions are often not extendible and use few abstractions - making them less interesting when comparing solutions across different languages.

FizzBuzzBazz is a variant of FizzBuzz which adds on additional rule - for multiples of 7, print Bazz. As such instead of the number 35, one would print BuzzBazz, as it is both a multiple of 5, and a multiple of 7. This adds just enough complexity as to make its different solutions interesting for comparison.

I challenge you to implement FizzBuzzBazz in the language of your choice, and find the shortest correct program you can come up with. Post your solution in the comments below, or tweet with the hashtag #fizzbuzzbazz - I will update this page to show the shortest program submitted.

Current winner: 62 characters.

The rules of FizzBuzzBazz stand as follows:

  • Print a list from 1 to 100 - except in the following cases, where instead of the number you should print:
  • For multiples of 3, print Fizz.
  • For multiples of 5, print Buzz.
  • For multiples of 7, print Bazz.
  • For any combination of the above, print the combined string, in the above order. Thus instead of 21, print FizzBazz, at is both a multiple of 3, and a multiple of 7.
  • An expression which evaluates to a list of the results is acceptable and in fact preferred.

Solution in LiveScript

My solution in LiveScript is 64 characters (can you beat that in the language of your choice?):

[1 to 100]map ->[k+\zz for k,v of{Fi:3,Bu:5,Ba:7}|it%v<1]*''||it

The solution is not in the recommended style, but in the interest of brevity I have removed optional characters.

LiveScript is a language which compiles to JavaScript. It has a straightforward mapping to JavaScript and allows you to write expressive code devoid of repetitive boilerplate. While LiveScript adds many features to assist in functional style programming, it also has many improvements for object oriented and imperative programming.

Now, for an explanation:

  1. We have to print a list 100 items in a accordance with a certain set of rules. Our starting point is thus a list of the numbers from 1 to 100. To do this we will use a range literal:

    [1 to 100]
    
  2. We want to create a new list of the same amount of items by applying the same rule to each member of the list. For this we can use the map function, which is a property of all arrays in the newer versions of JavaScript (and thus LiveScript).

    [1 to 100].map(...)
    
  3. map takes a function as its argument, which it applies to each of member of the inputted list. The function which map takes must have a single argument, and return a value which will be in corresponding value in the outputted list. In LiveScript, functions are defined with an arrow, pointing from the arguments to the function body.

    [1 to 100].map((x) -> ...)
    
  4. But how will decide what to return for each input to our map function?

    The rules stipulate that for multiples of 3, we print Fizz, for multiples of 5, we print Buzz, and for multiples of 7, we print Bazz. We can represent this relationship with an object literal:

    {Fizz: 3, Buzz: 5, Bazz: 7}
    
  5. We need to transform this set of rules into output. As it is possible to have a number which is a multiple of more than one of those numbers, it is possible for more than one of the rules to pass. Thus, we must filter the object and produce a list of the results. An empty list will be the case when none of the rules pass.

    To do this we can use a list comprehension over the object. Using of gives us both the key and value for each item in the object. We want to output the key (eg. Fizz) by filtering using a certain set of rules upon the value (eg. 3). The format is [output for values of input when condition]

    [key for key, value of {Fizz: 3, Buzz: 5, Bazz: 7} when ...]
    
  6. The condition is fairly straight forward, a number is a multiple of another if there is no remainder when divided. (Remember x is the value we are mapping over.)

    [key for key, value of {Fizz: 3, Buzz: 5, Bazz: 7} when x % value == 0]
    
  7. This results in a list, but we do not want a list, we need a string. We thus join the list.

    [key for key, value of {Fizz: 3, Buzz: 5, Bazz: 7} when x % value == 0].join('')
    
  8. Putting together what we have so far - note that LiveScript implicitly returns the last expression in the function body (unless otherwise specified), so no return statement is required.

    [1 to 100].map((x) ->
      [key for key, value of {Fizz: 3, Buzz: 5, Bazz: 7} when x % value == 0].join('')
    )
    
  9. The above doesn't give us what we want though - instead of printing an empty string when none of the rule pass, we want to print the number being inputted. In JavaScript, an empty string is "falsy". Thus, we can use the or operator - it evaluates to the left hand side when the left is truthy, and the right hand side when the left is falsy.

    [1 to 100].map((x) ->
      [key for key, value of {Fizz: 3, Buzz: 5, Bazz: 7} when x % value == 0].join('') or x
    )
    

    It works! The above evaluates to a list with the proper results. However, it is a bit long, 109 characters, so we can shorten it up a bit.

  10. First, parentheses are not required when calling a function in most cases.

    [1 to 100].map (x) ->
      [key for key, value of {Fizz: 3, Buzz: 5, Bazz: 7} when x % value == 0].join('') or x
    
  11. We can also shorten up the variable names we are using:

    [1 to 100].map (x) ->
      [k for k, v of {Fizz: 3, Buzz: 5, Bazz: 7} when x % v == 0].join('') or x
    
  12. When a function has only one argument, we can use it to implicitly refer to that argument without explicitly defining it. Thus it replaces x in this case.

    [1 to 100].map ->
      [k for k, v of {Fizz: 3, Buzz: 5, Bazz: 7} when it % v == 0].join('') or it
    
  13. If the right hand side of the multiplication op * is a string literal, then it acts to join the list on the left hand side. We can thus replace .join('').

    [1 to 100].map ->
      [k for k, v of {Fizz: 3, Buzz: 5, Bazz: 7} when it % v == 0] * '' or it
    
  14. | is an alias for when.

    [1 to 100].map ->
      [k for k, v of {Fizz: 3, Buzz: 5, Bazz: 7} | it % v == 0] * '' or it
    
  15. For our purposes we do not need worry about negative numbers, and we are dealing with only integers, so < 1 is equivalent to == 0.

    [1 to 100].map ->
      [k for k, v of {Fizz: 3, Buzz: 5, Bazz: 7} | it % v < 1] * '' or it
    
  16. We're doing pretty good, but we can go further. Dots are optional in unambiguous situations, so we can shorten up the map property access.

    [1 to 100]map ->
      [k for k, v of {Fizz: 3, Buzz: 5, Bazz: 7} | it % v < 1] * '' or it
    
  17. Factoring out the zz found in all our rules, using a a word literal in the form of \word, leaves us with:

    [1 to 100]map ->
      [k + \zz for k, v of {Fi: 3, Bu: 5, Ba: 7} | it % v < 1] * '' or it
    
  18. Finally, we can remove a bunch of whitespace. Because or requires whitespace around it, we can swap it out for || which does not.

    [1 to 100]map ->[k+\zz for k,v of{Fi:3,Bu:5,Ba:7}|it%v<1]*''||it
    

The final result of our code golf efforts: a total of 64 characters.

Note that our solution is easily extensible as our rules are stated as data rather than imperative code.

Current Winner - LiveScript - 62 Characters

Thank you to Ian Barfield for creating an even shorter solution in LiveScript!

[++x>?[k+\zz for k,v of{Fi:3,Bu:5,Ba:7}|x%v<1]*'' for x to 99]

So far, the LiveScript solution of 62 characters is the shortest working FizzBuzzBazz program. Think you can beat it in the language of your choice? Enter your attempt in the comments below, or tweet with the hashtag #fizzbuzzbazz. If a shorter program is found, I'll update this section with the new results. For more information on LiveScript, check out its official site. If you are interested in functional programming, you may want to check out Functional Programming in JavaScript using LiveScript and prelude.ls.


For more on LiveScript and prelude.ls, .

comments powered by Disqus