とんちゃんといっしょ

Cloudに関する技術とか日常とかについて書いたり書かなかったり

FizzBuzzについて考えてみた

全てのことの発端はこのブログだと思う。
どうしてプログラマに・・・プログラムが書けないのか?


個人的にはプログラムの多くの処理は制御と条件分岐で成り立ってる思ってる。


FizzBuzzには制御(繰り返し処理)と条件分岐が必要となるため、
これができるかできないかでプログラム能力があるかないかがわかるわけだ。


逆に考えればこれができればプログラムの基礎的なことがわかっているとも言える。
じゃあこれを教材にすればいいのではないかと思った。

class FizzBuzz{

    private static void printFizzBuzzV1(){
        for(int i = 1; i <= 100; i++){
            if(i % 15 == 0){
                System.out.println("FizzBuzz");
            }else if(i % 3 == 0){
                System.out.println("Fizz");
            }else if(i % 5 == 0){
                System.out.println("Buzz");
            }else{
                System.out.println(i);
            }
        }
    }

    private static void printFizzBuzzV2(){
        for(int i = 1; i <= 100; i++){
            String ans = "";
            if(i % 3 == 0) ans += "Fizz";
            if(i % 5 == 0) ans += "Buzz";
            if(ans.equals("")) ans += i;
            System.out.println(ans);
        }
    }


    private static void printFizzBuzzV3(){
        for(int i = 1; i <= 100; i++)
            System.out.println(i%3<1?i%5<1?"FizzBuzz":"Fizz":i%5<1?"Buzz":i);
    }

    public static void main(String[] args){
        printFizzBuzzV1();
        printFizzBuzzV2();
        printFizzBuzzV3();
    }
}


FizzBuzzの問題文をそのまま実装するのならば多分V1のような実装になると思う。

    private static void printFizzBuzzV1(){
        for(int i = 1; i <= 100; i++){
            if(i % 15 == 0){
                System.out.println("FizzBuzz");
            }else if(i % 3 == 0){
                System.out.println("Fizz");
            }else if(i % 5 == 0){
                System.out.println("Buzz");
            }else{
                System.out.println(i);
            }
        }
    }

まずはじめに、1〜100の繰り返しの処理を行う必要がある。
ここでwhile文を使おうがfor文を使おうが個人の好みだと思うが普通はforを使うはず。

ちなみにforの使い方は以下の通りである。

for(初期処理; 終了条件判定; 末尾処理){
  //処理内容
}

今回の初期処理は1~100ということでint型の変数iに1を代入する。
次に終了条件は100までということで、

for(int i = 1; i <= 100; i++)

ここで気をつけるべき内容としては

× i < 100
○ i <= 100

上ではiが100より小さい(100未満)と言う判定のため、100自身が含まれない。
下はiが100以下という判定のため、100自身が含まれる。


プログラムを始めたばかりの頃は<を使うべきなのか<=を使うべきなのかの判断が難しい。
そのためバグが生じやすいのはだいたいこうした判定文まわりになる。

次に気にしたいのがプログラムの処理の順番。
ここで注意するべきは先に15で割り切れるかを判定すること。
多くのプログラミング言語は上から順に計算が行われる。


そのため、3や5で割り切れるかと言った判定分を先に書いてしまうと、
15で割り切れる数は先に3や5で割り切れるために15で割り切れるかの判定が行われないまま、
処理が行われる。


つまり、まずはプログラムがどのような順に実行されているかを意識していなければ、
ここでつまずくことになる。


しかし、V1はあまりにきれいなコードとは言えない。
というわけで、V2の用なコードを書いてみた。

    private static void printFizzBuzzV2(){
        for(int i = 1; i <= 100; i++){
            String ans = "";
            if(i % 3 == 0) ans += "Fizz";
            if(i % 5 == 0) ans += "Buzz";
            if(ans.equals("")) ans += i;
            System.out.println(ans);
        }
    }

繰り返しの処理に関してはV1と同じ。
処理が違っている部分としては以下の数点

  • String型の変数ansを使って出力する文字を決める
  • iが3で割り切れるときansに"Fizz"を追加
  • iが5で割り切れるときansに"Buzz"を追加
  • ansが空のときansに現在のカウントであるiを追加
  • 最後にansを出力する


これがベストかと問われるとよくわからないが、
少なくとも何も考えていないV1よりはスマートな解答だと思う。


FizzBuzzを通して問題を解くだけでなく、
問題の解き方をみることでその人のプログラミング能力のレベルもわかる気がする。
定期的にFizzBuzzのような問題を解いてみて、
自分がどういったレベルなのかを把握するのもありなのではないかと思う。


最後のおまけとしてShort Codingしておく。

    private static void printFizzBuzzV3(){
        for(int i = 1; i <= 100; i++)
            System.out.println(i%3<1?i%5<1?"FizzBuzz":"Fizz":i%5<1?"Buzz":i);
    }

どうしてこうなったかは自分で考えてみよう。