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以外に出力したい文字列が増えた場合などは、配列とビット演算の二箇所を修正しなければいけないので、拡張性は落ちますね。

また、良い方法が見つかれば記事にしてみたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください