【PHP】FizzBuzz問題を解いてみた。【具体的解説付き】


・動作環境 PHP7

プログラミングの世界で最低限の実力を持っているかどうかを測る指標のような存在であるFizzBuzz問題を解いてみました。
以下に解くまでの過程と考え方も併せて解説致します。

なお「最低1回forとif文でコードを記述した事のある人向け」の解説となっています。
どうしてFizzBuzzがそのソースコードで成立するのか理解する助けになればと思います。

PHPにおけるFizzBuzz問題の答え

fileName.php
<?php

echo "FizzBuzz問題";
echo PHP_EOL;

for($i = 1; $i <=100; $i++){
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }
}

?>

以下解説。

その1 : For文

fileName.php
<?php
for($i = 1 ; $i <= 30 ; $i++){
  条件式
}
?>

Forはループを作り出すのに用います。
なお上記のforに続く()の中身を訳しますと、

1、「$i = 1」最初は$iに1を入れる。そしてまずはそれを出力。
2、「$i <= 30」以降の繰り返し処理で$iの中身が30を超えない限り出力を繰り返す。
3、「$i++」なお1回繰り返す毎に1を足していく。

という処理内容です。
なので上記の場合1~30までの数字が出力されます。

forは「n番目まで続く連続した数列を作る」とか、「n回同じ処理を必要とする」場合に用いられる訳です。

その2 : if文

一番上の答えの中でif文は以下の部分にある事が解ります。

for($i = 1; $i <=100; $i++){
 「この部分がif文」
}

ここからはその部分の解説をします。

filename.php

    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }

なおそもそもの挙動としてif文は以下のように、順番に処理をしている事になります。

1、(今回の場合)最初のfor文で出てきた数字を受け取る。
2、if文の中身のソースコードを上から順番に処理し、該当部分が出たらその処理内容を出力する。
3、出力処理がされたらそこで計算は一旦終了。1に戻りfor文の記述に従い、次の数字を受け取る。

つまり今回のソースコードの場合は、「1をifで処理し、2をifで処理し、3をetc…」 という処理をしていた事になります。

ifでの処理の順番

次に処理の順番です。
結論から言うと、

1、if文で15の倍数を検知して”FizzBuzz”を出力。
2、3の倍数を検知して"Fizz"を出力。
3、5の倍数を検知して"Buzz"を出力。
4、上記に該当しなかった場合そのまま数字を出力。

この順番で処理します。

また、FizzBuzz問題を解く際は、「集合」を気にしてみるのが良いと感じました。
高校数学Aでやったあの集合です。

四角形の中に〇が2つ描かれていて、その丸同士が重なっている図を1度は見た事があると思います。

その図の丸が重なった部分から処理し、次に丸単体を処理し、最後に丸に該当しない数字を順番に書き出せばよいのです。
そうすれば重なった部分を重複処理する事を避ける事ができます。

図で集合を解説

上記の図は、
・forの四角い枠が全ての数字。
・3nの円が3の倍数。
・5nの円が5の倍数。
・そして3と5が重なる部分が15の倍数
という事になります。

今回はこの図を使って解説します。

計算部の考え方

ところでFizzBuzz問題は3の倍数や5の倍数や15の倍数の時に表現をFizzやらBuzzにすり変えよという問題です。
この場合、複数条件が重なった部分を出力し、次に単体で条件に重なるものを順番に出力して、最後にどの条件にも合致していない数字を出力すればよいのです。

従って、
1、計算部の重なっている部分の15n(3の倍数かつ5の倍数である15nの部分)をまず出力
2、3nの部分を出力
3、5nの部分を出力
4、3倍でも5倍でもない数字を出力
※2と3は重なり合った部分ではないので順番が逆でもOK!

という順番に処理を行えば、FizzBuzzが完成するという訳です。

if文の仕様

「え?15の倍数を処理できても、それらは3の倍数とか5の倍数でもあるのだから"FizzBuzzFizz"みたいな出力にならないか?」
と考えたかもしれませんが、ご安心を。

if文は、1度処理に成功したら以降の処理をしないという仕様です。

処理時に数字が15の倍数であると解ればFizzBuzzを出力して、以降にある3の倍数・5の倍数の処理層にはそもそも計算が行かないのです。
それを考慮しながら下記のif文をもう一度ご覧ください。

filename.php

    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }

if文は、例えるのなら”フィルター”に近いです。

・最初が15の倍数というフィルターで該当したらそこで処理。
・次が、3と5の倍数というフィルターで該当したらそこで処理。
・そして最後の"}else{"以降で、どのフィルターにも当てはまらない数字を処理。

となります。

最後までフィルター(15の倍数/5の倍数/3の倍数)にかからなかった数字が最後の処理層に届く訳です。

間違い等ありましたらお気軽にコメント欄へお申し付けください。