PHP で FizzBuzz問題を “条件分岐無し” でやってみよう
2019-05-07
以前勉強会で扱ったネタで、 FizzBuzz問題を “if文を使わずに” PHPで実装する、ということをやりました。
この時は、 “オブジェクト指向” の考え方を織り交ぜながら進めていき、最終的にif文を消していくことで拡張性を高める、という流れにしていました。
一方で、三項演算子(?:
)は使っていて、完全に条件分岐を無くすことはできませんでした。
ということで、今回は一旦 “オブジェクト指向” の方を諦めて、完全に条件分岐を無くすコードを考えてみました。
目次
念の為のFizzBuzz問題の説明
今更な感じですが、以下のルールを満たすプログラムを作ろう、というものです。
- 数字を1~100まで与えた時に、以下の条件に従って文字を出力する。
- 3の倍数の時に “Fizz” と出力
- 5の倍数の時に “Buzz” と出力
- 3の倍数かつ5の倍数(つまり15の倍数)の時に “FizzBuzz” と出力
- それ以外の場合には与えられた数値を出力
非常にシンプルで、そこそこに条件も織り交ぜられており、プログラミング言語の特性を掴んだり、実装方針の複雑さを考える時によく利用されるテーマですね。
条件分岐の無いFizzBuzzのコード
では、早速コードを見てみましょう。
<?php // 基本となるタイプの定義 $fizzBuzzTypes = [ 1 => 'Fizz', 2 => 'Buzz', 3 => 'FizzBuzz' ]; for ($num = 1; $num <= 100; $num++) { // 要素0に対象の値を格納 $fizzBuzzTypes[0] = "$num"; // 対象の値を添字へ換算 // 5の倍数の剰余の有無を第二ビット、 // 3の倍数の剰余の有無を第一ビットとすることで、 // 添字の0~3を表現する。 $index = intval($num % 5 === 0) << 1 | intval($num % 3 === 0); // 表示 echo $fizzBuzzTypes[$index] . PHP_EOL; }
コード量はかなり少ないので、わかりやすいかと思います。
配列の $fizzBuzzTypes
に出力したい文字を格納しておき、値を添字に換算していくことで条件分岐を無くしています。
ビット演算を使って表現しているので、FizzBuzz以外に出力したい文字列が増えた場合などは、配列とビット演算の二箇所を修正しなければいけないので、拡張性は落ちますね。
また、良い方法が見つかれば記事にしてみたいと思います。