ピティナ開発者ブログ

全日本ピアノ指導者協会のIT担当者が気まぐれにつづる技術系中心のブログです


FileMakerProでFizzbuzz問題

前置き

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

FileMakerPro とは

FizzBuzz とは

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

下準備と条件

基本骨子

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

f:id:ptna_it:20180806103417p:plain

条件

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

パターン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
)

f:id:ptna_it:20180806103436p:plain

これで実行すると……

f:id:ptna_it:20180806103445p:plain

できました。
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にしていきなり下準備の基本骨子を使わないやり方になってしまったという……(基本骨子は次の段でもう一度出てきます!)

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

f:id:ptna_it:20180806103506p:plain

では次に、 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 )
)

結果は以下。

f:id:ptna_it:20180806103518p:plain

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

改行記号の失敗例

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

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

これの出力結果は、

f:id:ptna_it:20180806103533p:plain

となります。残念ながら改行記号が半角スペースに解釈されてしまうのですね。なので、最初の成功例で出したように 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 & ")" )

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

f:id:ptna_it:20180806103548p:plain

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

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

f:id:ptna_it:20180806103602p:plain

よし、これで完璧だ!

f:id:ptna_it:20180806103619p:plain

……ん?

f:id:ptna_it:20180806103628p:plain

!!!

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

パフォーマンス計測

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

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

パターンA

7秒くらい。

f:id:ptna_it:20180806103638p:plain

パターンB

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

f:id:ptna_it:20180806103646p:plain

爆死パターン

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

f:id:ptna_it:20180806103657p:plain

結果まとめ

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

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

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

(著: Hiroyuki Noguchi)
この記事は現在0人が閲覧中