FizzBuzz 完成
15 のときだけ、なぜか Fizz で止まる
FizzBuzz を書いて最初につまずくのは、たいていここです。3 の倍数の判定を上に置くと、15 はその時点で捕まってしまい、"FizzBuzz" の枝には一生たどり着きません。
原因は if / else if の性質です。上から順に評価され、最初に当たった 1 つだけが実行されて、残りは見向きもされません。小さい数字で試しているうちは正しく動くので、15 を入れるまで気づきません。
広い条件を先に書くと、細かい条件に届かない
数字と言葉を変えて、同じ事故を再現してみます。
Java
// 6 の倍数なのに Two で捕まる
if (i % 2 == 0) {
System.out.println("Two");
} else if (i % 6 == 0) {
System.out.println("Six"); // ここには来ない
}6 は 2 の倍数でもあるので、上の枝で拾われて下には流れません。直し方はひとつで、条件の厳しい順に並べることです。6 の判定を上に持ち上げれば、6 は Six、4 は Two と正しく分かれます。
FizzBuzz でも起きているのは同じことです。15 は 3 の倍数でも 5 の倍数でもあるので、15 を先頭に置くか、3 の倍数かつ 5 の倍数という形で先頭に書きます。
倍数の判定に使うのは剰余演算子 % でした。割ったあまりが 0 なら、割り切れたということです。
Java
System.out.println(9 % 3); // 0 なので 3 の倍数
System.out.println(10 % 3); // 1 なので 3 の倍数ではないi <= n か i < n か
fizzbuzzList(5) は 5 まで含めた結果を返します。for (int i = 1; i < n; i++) と書くと 4 で止まり、"1 2 Fizz 4" になってテストが落ちます。for を書いたら、最初の i は何か、最後の i は何かを口に出して確かめる。これだけで境界のずれはほぼ防げます。
やってみよう
Solution.fizzbuzzList(int n) を完成させましょう。1 から n まで回して、各数字を FizzBuzz のルールで置き換えた文字列を、半角スペース区切りでつなぎます。
判定の順番を決めるのが山場です。書く前に、i が 15 のときにどの枝を通ってほしいかを紙に書いてから始めてください。
つなぎ方は「カウントダウン」の回と同じ問題が出ます。区切りを足しながらつなぐと末尾に 1 つ余るので、あとから落とすか、2 個目以降の前に置くか、どちらかで手当てします。fizzbuzzList(1) のように要素が 1 個だけのケースが、その手当てを確かめる一番よいテストです。
要件
- クラス名は
Solution、メソッド名はfizzbuzzList、引数はint n1 つ、戻り値の型はString 1からnまでをforループで回し、各値を FizzBuzz ルールで変換した文字列を 半角スペース区切り でつなげること- 末尾に余分なスペースを残さないこと (
trim()を使うか、先頭判定方式でスペースを 2 番目以降の前に置く)
入出力例
fizzbuzzList(5) → "1 2 Fizz 4 Buzz"
fizzbuzzList(15) → "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz"
fizzbuzzList(3) → "1 2 Fizz"
fizzbuzzList(1) → "1"
fizzbuzzList(10) → "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz"