14

I just came home from a job interview, and the interviewer asked me to write a program:

It should, count from 1 to 100, and print...

If it was multiple of 3, "ping"
If it was multiple of 5, "pong"
Else, print the number.

If it was multiple of 3 AND 5 (like 15), it should print "ping" and "pong".

I chose Javascript, and came up with this:

for (x=1; x <= 100; x++){
    if( x % 3 == 0 ){
        write("ping")
    }
    if( x % 5 == 0 ){
        write("pong")
    }
    if( ( x % 3 != 0 ) && ( x % 5 != 0 ) ){
        write(x)
    }
}

Actualy, I left very unhappy with my solution, but I can't figure out a better one.

Does anyone knows a better way to do that? It's checking twice, I didn't like it. I ran some tests here at home, without success, this is the only one that returns the correct answer...

Jared
  • 3,651
  • 11
  • 39
  • 64
BernaMariano
  • 846
  • 2
  • 9
  • 27

9 Answers9

23

Your solution is quite satisfactory IMHO. Tough, as half numbers are not multiple of 3 nor 5, I'd start the other way around:

for (var x=1; x <= 100; x++){
    if( x % 3 && x % 5 ) {
        document.write(x);
    } else {
        if( x % 3 == 0 ) {
            document.write("ping");
        }
        if( x % 5 == 0 ) {
            document.write("pong");
        }
    }
    document.write('<br>'); //line breaks to enhance output readability
}​

Fiddle

Also, note that any number other than 0 and NaN are truthy values, so I've removed the unnecessary != 0 and some pairs of parenthesis.


Here's another version, it doesn't make the same modulus operation twice but needs to store a variable:

for (var x=1; x <= 100; x++) {
    var skip = 0;
    if (x % 3 == 0) {
        document.write('ping');
        skip = 1;
    }
    if (x % 5 == 0) {
        document.write('pong');
        skip = 1;
    }
    if (!skip) {
        document.write(x);
    }
    document.write('<br>'); //line breaks to enhance output readability
}

Fiddle

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • Not that different from mine, but still better, as I asked for. Thanks – BernaMariano Dec 12 '12 at 17:58
  • Yes, I've thought about it in many ways but all the simple logic ones require 2 checks. I've only added an `else` micro-optimization, as I said, your code is pretty satisfactory IMO. Sec I'll attempt to redo it in a single line of code, but that'd probably get you reproved. `=]` – Fabrício Matté Dec 12 '12 at 18:01
  • @BernaMariano updated answer, now it doesn't make the same calc twice, however it requires a variable. – Fabrício Matté Dec 12 '12 at 18:15
  • 1
    This is one line ;) : `for (var x=1, skip; x <= 100; x++, skip=0) ((x % 3 || document.write('ping') || (skip=1)) && (x % 5 || document.write('pong') || (skip=1)) && skip || document.write(x)) + document.write('
    ');`
    – Shmiddty Dec 12 '12 at 18:43
  • @Shmiddty Yup, that `
    ` really helps to read the output. I kept it separated from the main logic as the question didn't ask to print new lines. Adding the `
    ` makes it much more readable though. `=]`
    – Fabrício Matté Dec 12 '12 at 18:45
  • @Shmiddty That's a clever way to declare and reset the `skip` flag, nicely done. `=]` – Fabrício Matté Dec 12 '12 at 18:49
  • I wonder if you get extra points for minifying by hand: `for(var x=1,s,d=document,t=3,f=5;x<101;x++,s=0,t=x%3,f=x%5)((t||d.write('ping')||(s=1))&&(f||d.write('pong')||(s=1))&&s||d.write(x))+d.write('
    ');​`
    – Shmiddty Dec 12 '12 at 18:52
  • And one step further because I can! `for(var x=1;x<101;x++)document.write((((x%3?'':'ping')+(x%5?'':'pong'))||x)+'
    ');​`
    – Shmiddty Dec 12 '12 at 19:17
9

Here's my one-liner:

for(var x=1;x<101;x++)document.write((((x%3?'':'ping')+(x%5?'':'pong'))||x)+'<br>');

​ I'm using ternary operators to return either an empty string or 'ping'/'pong', concatenating the result of these operators, then doing an OR (if the number is neither divisible by 3 or 5, the result of the concatenation is '' which is FALSEY in javascript). When both cases are true, the result of the concatenation is 'pingpong'.

So basically it comes down to

'' || x         // returns x
'ping' || x     // returns 'ping'
'pong' || x     // returns 'pong'
'pingpong' || x // returns 'pingpong'
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
6

The best solution I came up with is this one:

for (var i = 1; i <= 100; i++) {
  var message = '';
  if (i%3 === 0) message += 'ping';
  if (i%5 === 0) message += 'pong';
  console.log(message || i);
}
TheSETJ
  • 518
  • 9
  • 25
1

Here's a solution which allows for a dynamic list of multiples without adding more conditionals.

// List of outputs
var outputs = [
    {mult: 3, str: 'ping'},
    {mult: 5, str: 'pong'}
    // {mult: 10, str: 'play'} ex: [30] => 'pingpongplay'
];

// Loop 100 times
for (var i = 1, j = 100; i <= j; i += 1) {

    // Set empty vars
    var result, string = '';

    // Loop through the listed output objects
    outputs.forEach(function (output) {

        // If listed multiple, concat string
        if (i % output.mult === 0) {
            string += output.str;
        }

    });

    // Set result
    if (string.length) {
        result = string;
    } else {
        result = i;
    }

    // print result
    document.body.innerHTML += result + '<br>';
}

And as a function which passes jslint:

/*jslint browser: true */
var printOutputs = function (array, iterations) {
    'use strict';
    var i = 1;
    var outputResults = function (arr, idx) {
        var result;
        var str = '';
        arr.forEach(function (item) {
            if (idx % item.mult === 0) {
                str += item.str;
            }
        });
        if (str.length) {
            result = str;
        } else {
            result = idx;
        }
        return result;
    };
    while (i < iterations) {
        document.body.innerHTML += outputResults(array, i) + '<br>';
        i += 1;
    }
};
var outputs = [
    {mult: 3, str: 'ping'},
    {mult: 5, str: 'pong'}
];
printOutputs(outputs, 100);

And for fun, a minified ES6 version:

const pO=(arr,itr)=>{let i=1,o=(a,idx)=>{let r,s='';a.map(v=>{if(idx%v.mult===0)s+=v.str});s.length?r=s:r=idx;return r};while(i<itr){document.body.innerHTML+=`${o(arr,i)}<br>`;i++}};
pO([{mult:3,str:'ping'},{mult:5,str:'pong'}], 100);
SomeGuy
  • 11
  • 1
  • 1
0

I wrote a few variations on this (using fizz and buzz) as a benchmark to consider different ways of iterating over conditional logic.

while won again:

// Iterate using a recursive function
// firing a callback once per iteration

function f(s,n) {
    if(++n >= 102) return;
    s === '' ? console.log(n-1) : console.log(s);
    !!(n % 3)
        ? !!(n % 5)
            ? f('',n) : f('Buzz',n)
        : !!(n % 5)
            ? f('Fizz',n) : f('FizzBuzz',n);
}

// Iterate using a `while` loop
// firing a callback after satisfying a condition

function b(n) {
    var i = n;
    $:
        while(++i) {
            if(i % 3)
                if(i % 5) 
                    console.log(i);
                else 
                    console.log('Buzz');
            else if(i % 5) 
                console.log('Fizz');
            else 
                console.log('FizzBuzz');
            if(i >= 100) 
                break $;
        }
    return;
}

// Iterate using a `for` loop
// firing a callback once per iteration

function F(n) {
    var i = n, f = 'Fizz', b = 'Buzz', o = '';
    for (; i <= 100; i++) { 
        o = !(i % 3) 
            ? !(i % 5) 
                ? f + b : f 
            : !(i % 5) 
                ? b : i; 
        console.log(o);
    }
    return;
}

// Iterate using a `for` loop
// firing a callback after satisfying a condition

function B(n) {
    var i = n;
    var fiz = 'Fizz';
    var buz = 'Buzz';
    for(; i <= 100; i++)
        if(!(i % 3))
            if(!(i % 5))
                console.log(fiz + buz);
            else
                console.log(fiz);
        else if(!(i % 5))
            console.log(buz);
        else
            console.log(i);
    return;     
}


f('', 1); // recursive
b(0);     // `while`
F(1);     // `for`
B(1);     // `for

Benchmark: http://jsperf.com/fizzbuzz-mod

Benny Schmidt
  • 3,230
  • 1
  • 19
  • 14
  • Update: After more tests on different browsers, the third method is starting to pull away from the others in terms of operations-per-second. The outlying difference being that it 'deduces' first by running through all logic, and then firing a single callback. Interesting to note. What I'd be interested in seeing (if someone is up for it), is an example using inverse loops (e.g. `while(i--)`) to see if it's any more performant. – Benny Schmidt Mar 03 '13 at 20:54
  • before I saw this code I didn't understand why does everyone so pissed about ternary operator – ganqqwerty Jul 14 '17 at 19:02
  • @ganqqwerty lol yeah i was having too much fun with that in 2013... ive since eased off such syntactic madness, however, now that react/functional style is popular it's making quite a comeback in front-end xD – Benny Schmidt Jul 15 '17 at 19:19
0

//create a for loop to count from 0 to 100
       for (let num = 0; num <= 100; num++){
        /**As the count increments, if the number is divisible by 3 and divisible by 5
        print FizzBuzz, I have concatenated the number with FizzBuzz for clarity. 
        Use % instead of \ to ensure it returns an int instead of float.**/
         if ((0 == num % 3) && (0 == num % 5)){
           console.log ("FizzBuzz" + " " + num); 
//otherwise, if the number is divisible by 5 print Buzz
         } else if (0 == num % 5) {
          console.log("Buzz" + " " + num);
//Also, if the number is divisible by 3 print Fizz
         } else if (0 == num % 3){
           console.log("fizz" + " " + num);
         } else {
//meanwhile, still print all the numbers that don't satisfy the conditions above
           console.log (num);
         }
      }
Sambydev
  • 31
  • 2
-1
 for( int number = 1 ; number < 100 ; number++ )
    {
        boolean shouldPrintNumber = true;

        System.out.println("\n");
        if( (number%3) == 0 )
        {
            System.out.print("ping");
            shouldPrintNumber = false;
        }
        if( (number%5) == 0 )
        {
            System.out.print("pong");
            shouldPrintNumber = false;
        }

        if( shouldPrintNumber )
        {
            System.out.print( number );
        }

    }
-1
for var a = 1; a <= 100 ; a++
{
  if a % 3 == 0 && a % 5 == 0
  {
    println("Fizzbuzz")
    continue
  }
  if a % 5 == 0
  {
    println("Buzz")
    continue
  }
  if a % 3 == 0
  {
    println("Fizz")
    continue
  }
  else
  {
    println(a)
  }
}
Martin G
  • 17,357
  • 9
  • 82
  • 98
  • While this code block may answer the question, it would be a better answer if you could provide some explanation for **why** it does so. – DavidPostill Mar 06 '15 at 06:32
-2

To get rid of the last condition you might use continue:

for (x=1; x <= 100; x++){

    if( x % 3 == 0 ){
        write("ping")
        continue
    }
    if( x % 5 == 0 ){
        write("pong")
        continue
    }

    write(x)
}
powtac
  • 40,542
  • 28
  • 115
  • 170