【Java アルゴリズム修行③】分岐処理 ~FizzBuzzと閏年~


FizzBuzz

分岐処理の名問、FizzBuzz
1~入力された値までの数列で、下記条件に沿って出力を行えということ
(実務ではまずない要件ですが、レッツアルゴリズム!)

  • 3の倍数かつ5の倍数のときには、"FizzBuzz"
  • 3の倍数のときには、"Fizz"
  • 5の倍数のときには、"Buzz"

考え方としては至ってシンプルで、倍数であればつまりその数で割り切れるということなので
3の倍数であれば、3で割ったときの余りが0であれば良いということになります。

algo.java
import java.util.*;

public class Main {
        public static void main(String[] args) {
                Scanner sc = new Scanner(System.in);
                int number = sc.nextInt();
                //iは1からスタートして、入力値まで繰り返し処理を行う
                for(int i = 1; i <= number; 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);
                        }
                }
        }
}

見飽きてるでしょうし、解説する程でもないんですが、
個人的に更新文に数列の数を制御させることで、割とスッキリしたんじゃないかと思っています。(ど素人のドヤを受け入れてください)

初期化文 → 条件文 → 繰り返し処理 → 更新文
というJavaの繰り返し文法を使えばまとめてかけるのが便利ですね。。!

iを1からスタートさせて、条件分を i <= 入力値にすればiだけでいけましたね汗
@fujitanozomuさん、ご指摘ありがとうございます!)

考え方としては、下記画像のような条件分岐を else-if文を用いて表現しました。
3でも5でも割れるもの = 15の倍数なので、これを最初の条件式に持ってこないと期待通りにいかないので注意です。

閏年

入力された年が閏年か判定せよということ(ググれば一瞬で一覧が出てくるぞ)
閏年の条件は下記の通りですが、すいませんここまではググりました。。

  • 4で割り切れなければ平年
  • 4で割り切れるが、100で割り切れない場合は閏年

  • 4と100で割り切れたとしても、400でも割り切れる場合は閏年

上の条件が揃えばもう無敵だ!と調子に乗ってありのまま書いたコードがこちら

algo.java

import java.util.*;

public class Main {
        public static void main(String[] args) {
                Scanner sc = new Scanner(System.in);
                int year = sc.nextInt();
                if(year % 4 == 0){
                        if (year % 100 == 0 ){
                                if (year % 400 == 0){
                                 System.out.println("閏年です");
                                 }else{
                                        System.out.println("閏年ではありません");
                                        }
                        }else{
                                System.out.println("閏年です");
                                }
                }else{
                        System.out.println("閏年ではありません");
                }
        }
}

無心で条件に沿ってif文を連ねた結果こんな風になってしまいました。。
これがネストコードという誰も幸せにならないコードですね。
無鉄砲に書くことでいかに醜くなってしまうかがわかったところで、これを改善するために追加された else-if文を使っていきましょう。

ネストを改善してみる

algo.java
import java.util.*;

public class Main {
        public static void main(String[] args) {
                Scanner sc = new Scanner(System.in);
                int year = sc.nextInt();
                if(year % 4 != 0){
                        System.out.println("閏年ではありません");
                }else if (year % 100 != 0 ){
                        System.out.println("閏年です");
                }else if (year % 400 == 0){
                        System.out.println("閏年です");
                }else{
                        System.out.println("閏年ではありません");
                }

        }
}

まず最初に4で割り切れなければ、そのまま平年判定します。
4で割り切れても、100で割り切れなければ閏年判定。
4かつ100かつ400で割り切れた場合は閏年判定。
4かつ100で割り切れても、400で割り切れなければ平年判定。

という流れでロジックもコードの見栄えもかなりスッキリします。

学んだこと

  • 条件が複数あった場合でも、true/falseで条件分岐させつつ、最後のelse部分の結果が共通で締まるようにすれば整理しやすい。
  • ロジックが上から下へと一貫する形まで整理できたら、else-if文でまとめて書くことによってネストを回避しつつ、スッキリとしたコードが書ける。

やはりまずは動くコードを書いてみて、そこからもっとスッキリ書けないのか?という思考フローは悪くないな。。
と思いつつも、自分の初手が毎度ゴリ押しすぎてもうちょっとスマートにやれないのかとも思ってしまいますね汗 
引き続き頑張っていきます!