FizzBuzz
FileMaker

FileMakerProでFizzbuzz問題

前置き

  • FileMaker Pro で Fizzbuzz問題 (参照:wikipedia) やってみようかなと思いました。唐突に。
  • ついでに複数パターンでパフォーマンス測定もやってみます。
  • 同じようなことやってる人いないかと思って検索してみたら、以下が見つかりましたのでご紹介まで。

FileMakerPro とは

  • Apple の子会社である FileMaker 社が開発販売しているデータベースソフトのクライアント側。
  • スクリプトと呼ばれる処理の中で FizzBuzz 問題を解ける。
  • やろうと思えば、LetEvaluate という関数を用いて、計算式単体でもできる。今回やってみる。
  • 参照: 公式サイト - FileMakerPro

FizzBuzz とは

  • ルール
    • 1 から 100 までの自然数を列挙していく。
    • 3 の倍数では Fizz を出力する。
    • 5 の倍数では Buzz を出力する。
    • 3 と 5 の公倍数では FizzBuzz を出力する。
  • 参照: Wikipedia - FizzBuzz

下準備と条件

基本骨子

基本はスクリプトでやるので、まず、100回ループして改行区切りで 1~100 までの数字を書き出します。以下のような感じで。

image.png

条件

  • フィールドは結果を出力するための一つのみ使用する。
  • フィールドに値をセットするのは最後に一回だけ。

パターンA:Loop

やることは以下の通りです。

  • 1~100 までの数字を出力する
  • その途中で、以下の条件の際には出力する値を変える
    • 3の倍数であれば:Fizz
    • 5の倍数であれば:Buzz
    • 3と5の公倍数であれば:FizzBuzz

下準備の基本骨子から、 \$result に挿入していく値を \$i から \$value へ変更します。
\$value の計算式は以下のように。

Case (
  not Mod ( $i ; 15 ); "FizzBuzz";
  not Mod ( $i ; 5 );  "Buzz";
  not Mod ( $i ; 3 );  "Fizz";

    $i
)

image.png

これで実行すると……

image.png

できました。
FileMaker の Case について補足しておくと、上から順に評価されるもので、最初に評価されたところで抜けます。

あまりに簡単で、これだけで終わってしまうとつまらないので、別パターンも考えてみます。

パターンB:Let + Evaluate 関数による再帰

やることは以下の通りです。

  • 1~100 までの数字を出力する
  • その途中で、以下の条件の際には出力する値を変える
    • 3の倍数であれば:Fizz
    • 5の倍数であれば:Buzz
    • 3と5の公倍数であれば:FizzBuzz

パターンAと同じ。
ただし、スクリプトで Loop をまわすのではなく、一つの計算式内で Let + Evaluate 関数による再帰をおこないます。

まずは単純に、改行区切りで 1~100 までの数字が出力されるようにしましょう。計算式は以下のように。

Let (
  [
    $i = 1;
    $max = 100;
    $result = $i;

    $formula = "
      If (
        $i ≠ $max;
          Let (
            [
              $i = $i + 1;
              $result = $result & Char(10) & $i
            ];

            Evaluate ( $formula )
          );

          $result
      )
    "
  ];

  Evaluate ( $formula )
)

パターンBにしていきなり下準備の基本骨子を使わないやり方になってしまったという……(基本骨子は次の段でもう一度出てきます!)

結果は以下の通り、ちゃんと出力されてくれます。

image.png

では次に、 Fizz Buzz FizzBuzz への対応を入れましょう。

Let (
  [
    $i = 1;
    $max = 100;
    $result = $i;

    $formula = "
      If (
        $i ≠ $max;
          Let (
            [
              $i = $i + 1;

              $value = Case (
                         not Mod ( $i ; 15 ); \"FizzBuzz\";
                         not Mod ( $i ; 5 ); \"Buzz\";
                         not Mod ( $i ; 3 ); \"Fizz\";

                           $i
                       );

              $result = $result & Char(10) & $value
            ];

            Evaluate ( $formula )
          );

          $result
      )
    "
  ];

  Evaluate ( $formula )
)

結果は以下。

image.png

基本ロジックはほとんどパターンAと同じなので、面白味が薄いかもしれませんが……

改行記号の失敗例

ちなみに \$formula 定義内の \$result の定義について以下のようにしてしまうと、

$result = $result & \"¶\" & $i

これの出力結果は、

image.png

となります。残念ながら改行記号が半角スペースに解釈されてしまうのですね。なので、最初の成功例で出したように Char(10) を指定してあげる必要があります。

爆死パターン:Substitute

やることは以下の通りです。

  • 1~100 までの数字を出力する
  • 出力し終えた後で、以下の条件に当たる行の値を置換する
    • 3の倍数であれば:Fizz
    • 5の倍数であれば:Buzz
    • 3と5の公倍数であれば:FizzBuzz

なので、まず、下準備の基本骨子をそのまま使います。
ループが終わった後で Substitute の処理を噛ませます。そのためには Substitute 条件をループ中に出力してあげなくてはなりません。例えば \$substitute という変数を置いて、以下のように。

Case (
  not Mod ( $i ; 15 ); $substitute & "[" & $i & ";\"FizzBuzz\"];";
  not Mod ( $i ; 5 );  $substitute & "[" & $i & ";\"Buzz\"];";
  not Mod ( $i ; 3 );  $substitute & "[" & $i & ";\"Fizz\"];";

    $substitute
)

ループを抜けた後で、 \$substitute の末尾から ";" という文字列を除去したいので、以下の計算式で上書きします。

Left ( $substitute ; Length ( $substitute ) - 1 )

\$result の計算式は以下のようになります。

Evaluate ( "Substitute(\"" & $result & "\";" & $substitute & ")" )

ただしこれだと、出力結果が以下のようになってしまいます。改行区切りのはずが、いつの間にやら半角スペース区切りに変換されてしまっているのです。

image.png

なので \$result の計算式にもう少し手を加えて……

Substitute ( Evaluate ( "Substitute(\"" & $result & "\";" & $substitute & ")" ) ; " " ; ¶ )

image.png

よし、これで完璧だ!

image.png

……ん?

image.png

!!!

出力された各行についてはテキストとして取り扱われてしまうので、該当する数字が全て置換されてしまいます。
ざんねん!! わたしの ぼうけんは これで おわってしまった!!

パフォーマンス計測

最後に、パターンA、パターンB、爆死パターン、という3種類のパフォーマンスを計測してみます。
ルールは以下の通り。

  • ループで 1,000 回実行させてみて、どれくらい時間がかかるか

パターンA

7秒くらい。

image.png

パターンB

16秒くらい。遅っ!
FileMaker で再帰ループしようとすると、スタック溜まってどんどん遅くなっていってしまうのですよね……あまりやらない方が良いです。

image.png

爆死パターン

10秒くらい。
いや出力結果は失敗してるんですけれど、再帰使うよりは高速で処理できそうですね。

image.png

結果まとめ

パターン 処理速度
7秒
16秒
爆死 10秒

以上のような感じになりました。
まったくもって、奇を衒わずに大人しくスクリプトループ使えって話ですね。

今回、冗談のようなアホのような事例で遊んでみましたが、実際に何か作る際の手法として何かの参考になればと思います。