DEV Community

Cover image for [Challenge] 🐝 FizzBuzz without if/else
Keff
Keff

Posted on • Updated on

[Challenge] 🐝 FizzBuzz without if/else

This challenge is intended for Javascript, but you can complete it with any language you like and can.


Most of us will know the FizzBuzz game/exercise and probably have done it many times. It should be a simple and straightforward exercise for most developers...

BUT can you do it without using if/else statements?


Challenge Description

Write a program that outputs the string representation of numbers from 1 to N.

But for multiples of 3, it should output "Fizz" instead of the number and for the multiples of 5 output "Buzz". For numbers which are multiples of both 3 and 5, you should output "FizzBuzz".

Curveball: You must not use if/else statements, and ideally, no ternary operator.

Example:

const n = 15;

/* 
Return:
  [
    "1",
    "2",
    "Fizz",
    "4",
    "Buzz",
    "Fizz",
    "7",
    "8",
    "Fizz",
    "Buzz",
    "11",
    "Fizz",
    "13",
    "14",
    "FizzBuzz"
  ]
*/
Enter fullscreen mode Exit fullscreen mode

I will comment my solution in a couple of days.

💪 Best of luck! 💪


Credits:
Cover Image from https://codenewbiesite.wordpress.com/2017/01/29/fizz-buzz/

Top comments (93)

Collapse
 
stephanie profile image
Stephanie Handsteiner • Edited

Easy, just do it in CSS.

ol {
    list-style-type: inside;
}

li:nth-child(3n), li:nth-child(5n) {
    list-style-type: none;
}

li:nth-child(3n):before {
    content: 'Fizz';
}

li:nth-child(5n):after {
    content: 'Buzz';
}
Enter fullscreen mode Exit fullscreen mode

Needs some Markup to display obviously.

Collapse
 
ben profile image
Ben Halpern

Ha!

Collapse
 
nombrekeff profile image
Keff

Magnificent! I knew there were going to be really neat solutions!!

Thanks for sharing your solution 💪

Collapse
 
rushsteve1 profile image
Steven vanZyl

The cleanest and best FizzBuzz implementation I know of doesn't use any if statements at all. Actually it doesn't use any control flow at all in most languages.
The approach is fully described here: philcrissman.net/posts/eulers-fizz...

On my Repl.it I also have this same approach implemented in several other languages:
repl.it/@rushsteve1/

Collapse
 
coreyja profile image
Corey Alexander

This was great! Love it when there is a simple probable mathematic solution to these kinds of things!

Collapse
 
nombrekeff profile image
Keff

Me too, so clean! I love maths but I'm crap at it myself xD

Collapse
 
nombrekeff profile image
Keff

I did not know about this, thanks for sharing. I will remember this!

Collapse
 
agtoever profile image
agtoever • Edited

Holy sh*t, my other solution was really ugly! :-o
Here is a (much) better one (also in Python3):

def fizzbuzz(n):
    for i in range(1, n + 1):
        print([f'{i}', f'Fizz', f'Buzz', f'FizzBuzz'][(i % 3 == 0) + 2 * (i % 5 == 0)])

fizzbuzz(22)

This works using the property that True in Python has numerical value 1 and using f-strings in an array. The proper element in the array is chosen based on the mentioned property, checking for divisibility with 3 and 5.

Collapse
 
nastyox1 profile image
nastyox • Edited

logical operators

The second half of an "and" statement only evaluates if the first half is true.

for(var i = 1; i < 100; i++){
    !(i % 3) && document.write("fizz");
    !(i % 5) && document.write("buzz");
    i % 3 && i % 5 && document.write(i);
    document.write(" ");
}

...

for loops

For loops check your second declaration on each iteration. Force it to be false on the second iteration, and you've got something that'll check your condition a single time.

for(var i = 1; i < 100; i++){
    for(var j = 0; !j && !(i % 3); j++) document.write("fizz");
    for(var j = 0; !j && !(i % 5); j++) document.write("buzz");
    for(var j = 0; !j && i % 3 && i % 5; j++) document.write(i);
    document.write(" ");
}

...

arrays

Referencing an index that that exists gives you the value stored there, but referencing an index that doesn't exist gives you undefined. Use an "or" statement to give yourself a fallback value when this happens, and you'll be ready to go.

var fizz = ["fizz"], buzz = ["buzz"];
for(var i = 1; i < 100; i++) document.write((((fizz[i % 3] || "") + (buzz[i % 5] || "")) || i) + " ");

Or, fill an array with your options, and leverage the fact that true can be used as 1 in JavaScript to do some index-selection math.

var arr = [null, "fizz", "buzz", "fizzbuzz"];
for(var i = 1; i < 100; i++){
    arr[0] = i;
    document.write(arr[!(i % 3) + !(i % 5) * 2] + " ");
}

...

try/catch blocks

You can purposefully throw exceptions when a boolean is false by referencing a variable that doesn't exist (the "throwException" variable in this case).

function tryIf(test, pass, fail){
    try{
        !test || throwException;
        (fail || function(){})();
    }
    catch(e){
        pass();
    }
}

for(var i = 1; i < 100; i++){
    tryIf(!(i % 3), function(){
        document.write("fizz");
    });

    tryIf(!(i % 5), function(){
        document.write("buzz");
    });

    tryIf(i % 3 && i % 5, function(){
        document.write(i);
    });

    document.write(" ");
}

...

while loops

This is the same concept as for loops. Force the loop to stop after one iteration (this time with a break), and you've got something that'll check your condition a single time.

for(var i = 1; i < 100; i++){
    while(!(i % 3)){
        document.write("fizz");
        break;
    }

    while(!(i % 5)){
        document.write("buzz");
        break;
    }

    while(i % 3 && i % 5){
        document.write(i);
        break;
    }

    document.write(" ");
}

...

switch statements

Who could forget the classic alternative to if statements? Technically not even cheating!

for(var i = 1; i < 100; i++){
    switch(i % 3){
        case 0:
            document.write("fizz");
        default:
    }

    switch(i % 5){
        case 0:
            document.write("buzz");
        default:
    }

    switch(!(i % 3 && i % 5)){
        case false:
            document.write(i);
        default:
    }

    document.write(" ");
}
Collapse
 
nombrekeff profile image
Keff

Wow, those are some solutions right there! Thanks a lot for sharing and taking the time to explain it.

I did some silly stuff, just for fun lol:

function fizzBuzz(number = 100) {
    let current = 1;
    let string = '';

    while (current <= number) {
        string += current + ' ';
        current += 1;
    }

    string = string.trim()
        .replace(/[0-9]+/g, (match) => {
            const valueMap = ['FizzBuzz', match];
            const index = match % 15;
            return valueMap[index] || match;
        })
        .replace(/[0-9]+/g, (match) => {
            const valueMap = ['Fizz', match];
            const index = match % 3;
            return valueMap[index] || match;
        })
        .replace(/[0-9]+/g, (match) => {
            const valueMap = ['Buzz', match];
            const index = match % 5;
            return valueMap[index] || match;
        })

    return string.split(' ');
}
Collapse
 
rad_val_ profile image
Valentin Radu

Here's the simplest I can think of without any statements. 🙃

function run(n, i=1, j=1, k=1, acc=[]) {
  !j && k && acc.push('fizz')
  !k && j && acc.push('buzz')
  !k && !j && acc.push('fizzbuzz')
  k && j && acc.push(i)

    n - 1 && run(n - 1, i + 1, (j + 1) % 3, (k + 1) % 5, acc)
  return acc
}

console.log(run(30))
Collapse
 
nombrekeff profile image
Keff

Nice, recursion for the win 💪

Collapse
 
nombrekeff profile image
Keff

Thanks for sharing!

Collapse
 
vonheikemen profile image
Heiker • Edited

You can still have flow control with functions.

const troo = (iff, elz) => iff;
const falz = (iff, elz) => elz;
const choose = (value) => [falz, troo][Number(Boolean(value))];

const is_fizz = (n) => choose(n % 3 === 0);
const is_buzz = (n) => choose(n % 5 === 0);

const fizzbuzz = (n) =>
  is_fizz(n) (
    () => is_buzz (n) ("FizzBuzz", "Fizz"),
    () => is_buzz (n) ("Buzz", n),
  )
    .call();

const range = (end) =>
  new Array(end).fill(null).map((val, index) => index + 1);

range(15).map(fizzbuzz).join(", ");
Collapse
 
nombrekeff profile image
Keff

I liked this approach! Thanks for sharing!

Collapse
 
ehsan profile image
Ehsan Azizi • Edited

Here is an ugly solution in one line

for (let i = 1; i <= number; i++) {
  console.log((i % 3 === 0 && i % 5 === 0 && 'fizzbuzz') || (i % 3 === 0 && 'fizz') || (i % 5 === 0 && 'buzz') || i);
}
Collapse
 
shravan20 profile image
Shravan Kumar B

U aren't supposed to use Ternary Operator.

Collapse
 
ehsan profile image
Ehsan Azizi • Edited

Oh yeah! didn't notice that, I have updated my solution

Collapse
 
mintypt profile image
mintyPT

Here is some python for you :)

print([
  (not (i % 3) and not (i % 5) and "FizzBuzz") or
  (not (i % 3) and "Fizz") or
  (not (i % 5) and "Buzz") or
  i
  for i in range(1,16)])
Collapse
 
jpantunes profile image
JP Antunes

There was a similar and equally really good thread about a month ago that had some devilishly clever solutions... highly recommend it!

My contributions below:

//1
const fizzBuzz = n => {
    const mapper = (arr, modulo, txt) => arr
                                    .filter(e => e % modulo == 0)
                                    .forEach(e => arr[arr.indexOf(e)] = txt);
    let x = 1;
    const range = [...Array(n)].map(_ => x++)
    mapper(range, 15, 'FizzBuzz');
    mapper(range, 5, 'Buzz');
    mapper(range, 3, 'Fizz');
    return range.toString();
}

//2
const fizzBuzz = n => {
    let x = 1;
    const range = [...Array(n)].map(_ => x++);
    for (let i = 2; i <= n; i += 3) range[i] = 'Fizz';
    for (let i = 4; i <= n; i += 5) range[i] = 'Buzz';
    for (let i = 14; i <= n; i += 15) range[i] = 'FizzBuzz';
    return range.toString();
}

//3
const fizzBuzz = n => {
    const isFizzBuzz = n => ( {false: '', true: 'Fizz'}[n % 3 == 0] 
                            + {false: '', true: 'Buzz'}[n % 5 == 0] 
                            || n.toString() );
    let x = 1;
    return [...Array(n)].map(_ => isFizzBuzz(x++)).toString();                             
}

//4 ...originally from a Kevlin Henney presentation here: https://youtu.be/FyCYva9DhsI?t=1191
const fizzBuzz = n => {
  const test = (d, s, x) => n % d == 0 ? _ => s + x('') : x;
  const fizz = x => test(3, 'Fizz', x);
  const buzz = x => test(5, 'Buzz', x);
  return fizz(buzz(x => x))(n.toString());
}
Collapse
 
nombrekeff profile image
Keff

Nice stuff. I will be checking out the thread!

There have been some really clever solutions posted here as well.

Collapse
 
shravan20 profile image
Shravan Kumar B • Edited
function fizzBuzz(n){
   let arr = [ ];
   for(i=1 ; i<=n; i++){
      let flag = i%15==0 && arr.push('FizzBuzz') || i%5==0 && arr.push('Buzz') || i%3==0 && arr.push('Fizz');
      !flag && arr.push(i);
   }

 return arr;
}



console.log(fizzBuzz(15));

Manolo Edge
@nombrekeff

Collapse
 
martinsebastian profile image
Martin Sebastian • Edited
const fizzBuzz = (until) => {
      const fizz = ["Fizz", "", ""];
      const buzz = ["Buzz", "", "", "", ""];

      (function fizzybuzzy(current) {
         console.log(fizz[current % 3] + buzz[current % 5]  || current);

         return (current + 1 <= until) && fizzybuzzy(current + 1);
     })(0);
}

fizzBuzz(100);
Collapse
 
martinsebastian profile image
Martin Sebastian • Edited

Some improvement to my earlier version.

A) better (arguably, because way more cognitive load than the very simple one above)

const fizzBuzz = (until, current = 0, fizzbuzz = ["", "Fizz", "Buzz"]) => {
    const fizzybuzzy = () => fizzbuzz[!(current % 3) * 1] + fizzbuzz[!(current % 5) * 2]  || current;
    return (current + 1 <= until) && (console.log(fizzybuzzy()), fizzBuzz(until, current + 1));
}

fizzBuzz(100);

B) above one as 1 liner b/c hello perl

const devBuzz = (function i(u, c= 0, m=["", "dev", ".to"])  {(c+1<=u) && (console.log(m[!(c % 3)*1] + m[!(c%5)*2] || c), i(u,c+1));});

devBuzz(20);
Collapse
 
martinsebastian profile image
Martin Sebastian

Also thinking about overriding Number.prototype.toString makes a fun thingy. Maybe someone already did, but someone for sure should :D

Collapse
 
jselbie profile image
John Selbie • Edited

My javascript solution, modeled after my C++ solution and then reduced

function fizzbuzz(N) {
    for (let i = 1; i <= N; i++) {
         let fb = ["", "Fizz", "Buzz", i.toString()];
         console.log(fb[(!(i % 3) + 0)]+fb[((!(i % 5)) * 2)]+fb[(((i%3!=0) && (i%5!=0))+0) * 3]);
    }
}
Collapse
 
martis347 profile image
Martynas Kan

Really nice idea!

Here's how I did it 😁

const fizzBuzz = (number) => {
    const array = Array(number).fill(undefined).map((_, index) => index + 1);
    const fiz = array.filter(v => !(v % 3))
    const baz = array.filter(v => !(v % 5))
    const fizBaz = array.filter(v => !(v % 5) && !(v % 3))

    let result = {};
    for (let i of array) {
        result[i] = i;
    }
    for (let f of fiz) {
        result[f] = 'Fizz';
    }
    for (let b of baz) {
        result[b] = 'Buzz';
    }
    for (let fb of fizBaz) {
        result[fb] = 'FizzBuzz';
    }

    return Object.values(result);
}
Collapse
 
nombrekeff profile image
Keff

Glad you liked it!

I just published a new challenge if you want another one :)

Collapse
 
benwtrent profile image
Benjamin Trent • Edited

Clojure example.

I quite like Andrew's bit shift array example. Only think that its better to have a nil zeroth value so you get circuit breaking for free.

;; Array for grabbing appropriate string, if exists
(def fizzes [nil "Fizz" "Buzz" "FizzBuzz"])

;; boolean to integer conversion
(defn b-to-i [b]
  (bit-and 1 (bit-shift-right (Boolean/hashCode b) 1)))

(defn fizzit [n]
  (let [fizzed (b-to-i (= 0 (mod n 3)))                     ;1 if true
        buzzed (bit-shift-left (b-to-i (= 0 (mod n 5))) 1)  ;2 if true
        both (+ fizzed buzzed)]                             ;3 if both are true
    (or (get fizzes both) (str n)))
  )

(defn fizzbuzz [n]
  (map fizzit (range 1 (inc n))))

repl.it link

Collapse
 
wdhowe profile image
wdhowe

One of the ways in Clojure:

(defn divisible?
  "Determine if a number is divisible by the divisor with no remainders."
  [div num]
  (zero? (mod num div)))

(defn fizz-buzz
  "Fizz if divisible by 3, Buzz if divisible by 5, FizzBuzz if div by both, n if neither."
  [n]
  (cond-> nil ; threaded value starts with nil (falsey)
    (divisible? 3 n) (str "Fizz") ; if true, adds Fizz to the threaded value (nil)
    (divisible? 5 n) (str "Buzz") ; if true, adds Buzz to the threaded value (nil or Fizz)
    :always-true     (or n))) ; return the threaded value if not nil (Fizz/Buzz) or n

(let [start 1
      stop 20]
  (println "FizzBuzz:" start "-" stop)
  (doseq [x (range start (+ 1 stop))] (println (fizz-buzz x))))

Original idea seen here: clojuredocs.org/clojure.core/cond-...