LoginSignup
1
1

More than 3 years have passed since last update.

js で Fizz Buzz

Posted at

Fizz Buzz も知らないプログラマーなんて... みたいな記事を読んだ。

知らんかったので、やる。

Fizz Buzz ?

最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。ただし、3で割り切れる場合は「Fizz」(Bizz Buzzの場合は「Bizz」)、5で割り切れる場合は「Buzz」、両者で割り切れる場合(すなわち15で割り切れる場合)は「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。

このゲームをコンピュータ画面に表示させるプログラムとして作成させることで、コードが書けないプログラマ志願者を見分ける手法をJeff AtwoodがFizzBuzz問題 (FizzBuzz Question) として提唱した。

出典: Fizz Buzz - Wikipedia

なるほど。

JavaScript で実装

❶ 配列を作るパターン

  • オーソドックスに「連番の配列」を用意して評価。
function fizzBuzz(max) {
  return Array(max).fill().map((val, idx) => {
    const num = idx + 1;
    if (num % 15 === 0) return 'FizzBuzz';
    if (num % 3 === 0) return 'Fizz';
    if (num % 5 === 0) return 'Buzz';
    return num;
  });
}

console.log(fizzBuzz(30));

// 結果:
// [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz", 16, 17, "Fizz", 19, "Buzz", "Fizz", 22, 23, "Fizz", "Buzz", 26, "Fizz", 28, 29, "FizzBuzz"]

(補足) 連番配列の作り方は、どれがいい?

計測した中では、Array(arrayLength).fill().map((val, idx) => idx) が良さそう。

/**
 * 関数を指定回数実行し、平均実行時間を取得する
 * 
 * @param max 試行回数
 * @param func 実行する関数
 * @returns 平均実行時間 (ms)
 */
function getAvgRunTime(max, func) {
    let count = 0
    let timeArr = [];
    while (count < max) {
        let start = performance.now();
        let result = func();
        let end = performance.now();
        timeArr.push(end - start);
        count++;
    }
    return timeArr.reduce((acc, cur) => acc + cur) / timeArr.length;
}

// いろいろな「連番の配列を作る方法」を各 30 回実行し、それぞれの平均実行時間を出力
console.log(getAvgRunTime(30, () => Array(1000000).fill().map((val, idx) => idx) ));
console.log(getAvgRunTime(30, () => [...Array(1000000)].map((val, idx) => idx) ));
console.log(getAvgRunTime(30, () => Array.from(Array(1000000).keys()) ));
console.log(getAvgRunTime(30, () => [...Array(1000000).keys()] ));
console.log(getAvgRunTime(30, () => Array.from({length: 1000000}, (val, idx) => idx) ));

// apply 関数を使う方法は、生成する要素数が多いと Maximum call stack size exceeded などで失敗するので割愛
// console.log(getAvgRunTime(30, () => Array.apply(null, Array(1000000)).map((val, idx) => idx) ));
連番配列の生成方法 Chrome v84 Firefox v79
Array(1000000).fill().map((val, idx) => idx) 19 ms 👑 19 ms
[...Array(1000000)].map((val, idx) => idx) 19 ms 👑 22 ms
Array.from(Array(1000000).keys()) 28 ms 14 ms
[...Array(1000000).keys()] 38 ms 13 ms 👑
Array.from({length: 1000000}, (val, idx) => idx) 53 ms 15 ms

❷ ジェネレーター関数を使うパターン

  • メモリを無駄に使わないように。
function getFizzBuzzAnswer(num) {
    if (num % 15 === 0) return 'FizzBuzz';
    if (num % 3 === 0) return 'Fizz';
    if (num % 5 === 0) return 'Buzz';
    return num;
}

function* makeFizzBuzzIterator(start = 1, end = Infinity) {
    let num = start;
    while (num < end) {
        yield getFizzBuzzAnswer(num);
        num++;
    }
    return getFizzBuzzAnswer(num);
}

let iterator = makeFizzBuzzIterator(1, 30);

while (true) {
    let result = iterator.next();
    console.log(result.value);
    if (result.done) break;
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1