SAS言語でFizzBuzzを書く


SAS言語の理解のためにFizz Buzzを書いてみます。1から100まで数字を繰り返し評価し、3で割り切れる場合は"Fizz"、5で割り切れる場合は"Buzz"、その両方で割り切れる場合は"FizzBuzz"を出力します。

<br><br>

SAS言語は結果の出力先が多数存在します。把握のために、まずはHTMLとlogへ出力するコードを書いてみます。

## HTMLに FizzBuzz を出力する

HTMLに出力する場合のコードは下記で、途中で出てくる「output」は明示的な出力のタイミングを示しています。「proc」 はプロシージャ（Procedure）で、特定のタスクを実行するための機能やモジュールを示しています。「noobs」オプションは出力結果の行番号を非表示とする設定です。「run;」は指定した処理を実行するためのコマンドでプログラムを終了せずにそれ以前のコードを実行します。

```sas
/* HTMLにfizz buzz を出力する */
data fizzbuzz;
    /* ループ処理 */
    do i = 1 to 100;
        /* 3と5ともに割り切れるとき */
        if mod(i, 3) = 0 and mod(i, 5) = 0 then
            result = "FizzBuzz";
        /* 3で割り切れるとき */
        else if mod(i, 3) = 0 then
            result = "Fizz";
        /* 5で割り切れるとき */
        else if mod(i, 5) = 0 then
            result = "Buzz";
        /* いずれでもないとき */
        else
            result = put(i, 8.);
        /* タイミングを指定してデータセットに書き込む */
        output;
    /* ループ処理の終了 */
    end;
run;
/* fizzbuzzデータセットの内容を表示する。noobsオプションは行番号を非表示とする。 */
proc print data=fizzbuzz noobs;
    /* 出力する列を指定 */
    var i result;
run;
```

出力結果：
![result1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4003689/22d8e3a3-829a-4b3d-9a4f-3c3a080e3f06.png)

<br><br>

## logに FizzBuzz を出力する

logに出力する場合のコードは下記です。「put」は指定の内容をログに出力しています。

```sas
/* ログにfizz buzz を出力する */
data _null_;
    /* ループ処理 */
    do i = 1 to 100;
        /* 3と5ともに割り切れるとき */
        if mod(i, 3) = 0 and mod(i, 5) = 0 then
            put i ": FizzBuzz";
        /* 3で割り切れるとき */
        else if mod(i, 3) = 0 then
            put i ": Fizz";
        /* 5で割り切れるとき */
        else if mod(i, 5) = 0 then
            put i ": Buzz";
        /* いずれでもないとき */
        else
            put i ": ";
    /* ループ処理の終了 */
    end;
run;
```

出力結果：
![result2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4003689/4d13bf89-079e-49cb-87d2-672048dba6fb.png)

<br><br>

## FizzBuzz 応用編1

今度はもう少し凝って無限ループを特定条件で抜ける挙動と、select文で複数の条件を同時に判別する挙動で実装します。「length」は変数の長さの指定で、「length result $8」は変数「result」が8文字であることを指定しています。SAS言語の文字列型の変数は最初に変数へ格納された文字列が変数の長さを決定するため、代入時に文字列が途切れる事象が発生することがあります。あらかじめ「length」を用いて文字列の長さを任意の長さ（想定される最長）に指定していれば文字列が途切れることはありません。ループを途中で抜けるコマンドは「break」でなくSAS言語独自の「leave」です。

```sas
/* ログにfizz buzz を出力する */
data _null_;
    i = 1;
    /* resultの長さを指定 */
    length result $8;
    /* 無限ループ開始 */
    do while (1);
	    /* 結果を初期化 */
        result = '';
        /* FizzとBuzzの判定 */
        select;
            when (mod(i, 3) = 0 and mod(i, 5) = 0) result = 'FizzBuzz';
            when (mod(i, 3) = 0) result = 'Fizz';
            when (mod(i, 5) = 0) result = 'Buzz';
            otherwise result = put(i, 8.);  /* 数字そのまま表示 */
        end;
        /* 結果をログに出力 */
        put i= result=;
        /* iが100になったらループを終了 */
        if i = 100 then leave;
        i + 1;
    end;
run;
```

出力結果：

![result3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4003689/35095b02-7165-47ed-8476-e017987284f6.png)

<br><br>

## FizzBuzz 応用編2

今度はマクロ変数、ハッシュテーブルを用いて実装します。出力はHTMLです。「%let」はマクロ変数の宣言で、「&fizz」は事前に宣言したマクロ変数「fizz」を示します。

```sas
%let fizz = 3;  /* Fizzの条件 */
%let buzz = 5;  /* Buzzの条件 */
/* ハッシュテーブルを使用してFizzBuzzを判定 */
data fizz_buzz_result;
  /* 変数の長さを事前に指定 */
  length result $8;  /* resultの長さを8文字に指定 */
  /* ハッシュオブジェクトを宣言 */
  declare hash h();
  h.definekey('i');  /* iは判定対象の数字 */
  h.definedata('i', 'result');  /* i と result を格納 */
  h.definedone();
  /* FizzBuzzを計算し、ハッシュテーブルに格納 */
  do i = 1 to 100;
    result = '';  /* 初期化 */
    if mod(i, &fizz) = 0 then result = 'Fizz';  /* Fizzの条件 */
    if mod(i, &buzz) = 0 then result = catx('', result, 'Buzz');  /* Buzzの条件 */
    if result = '' then result = put(i, 8.);  /* FizzBuzzでない場合は数字をそのまま格納 */
    h.add();  /* ハッシュテーブルに追加 */
  end;
  /* ハッシュテーブルの内容をデータセットに変換 */
  rc = h.output(dataset: 'output');  /* ハッシュテーブルからデータセットへ出力 */
run;
/* データセットを並べ替え */
proc sort data=output;
  by i;  /* iで並べ替え */
run;
/* 結果を表示 */
proc print data=output;
run;
```

出力結果：

![result4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4003689/9536d0f7-df47-49d8-a9e3-4490628d2d5e.png)

<br><br>

## SAS言語の実行環境

SAS言語の動作環境は[Altair SLC 及び Altair Analytics Workbench](https://www.brainpad.co.jp/services/products/Altair.html)を使用しております。詳細や最新情報は[Altair公式サイト](https://www.altairjp.co.jp/altair-analytics-workbench/)をご覧ください。

## 動作確認を行なった環境
- MacBookPro（2020 M1）
    - RAM 16GB
    - macOS Sonoma 14.4.1
- Altair SLC 2024 (05.24.03.00.001528)
- Altair Analytics Workbench 5.24.3.0.1528-GA-release-2024.2