rex0220 計算式プラグイン テーブル行の科目時間数まとめ

計算式プラグインで、テーブル行の科目時間数をまとめて文字列に表示します。

# 概要

テーブル行毎の科目の時間数を文字列「まとめ」に集計します。

- まとめ例
    - 理科 1, 国語 1, ? 1, 社会 1, 算数 1
    - 社会 3, 国語 1, 理科 2

![2024-12-14_16h08_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c58b29d1-2f00-7b73-063e-2857ac1824f8.png)

![2024-12-14_16h18_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3e0692a9-86a8-9ff3-fd1f-adf10683e227.png)

# 計算式プラグイン設定

科目・時間を配列にまとめ、ループ処理で科目単位に時間を累計します。

![2024-12-14_16h12_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a1a2afd6-8a8d-e115-9093-596cd9ddb3a7.png)

```.js
// テーブル.まとめ SINGLE_LINE_TEXT
LET(
  subArr, ARRAY(科目１,科目２,科目３,科目４,科目５), // 科目配列
  hrsArr, ARRAY(時間１,時間２,時間３,時間４,時間５), // 時間配列
  dict, DIC(), // 辞書作成
  tmp, ARRAY_MAP(hrsArr, h, i, 
    LET(
      sbj, NVL(ARRAY_GET(subArr, i), "?"), // 科目取得
      hrs, NVL(h, 0), // 時間設定
      prev, NVL(DIC_ITEM(dict, sbj),0), // 累計時間
      IF(hrs > 0, DIC_ITEM(dict, sbj, prev + hrs)) // 科目集計
    )
  ), // 配列マッピング
  JOIN(ARRAY_MAP(
     DIC_KEYS(dict), k, k & " " & DIC_ITEM(dict,k) // 出力文字
  ), ", ")
)
```

# 計算式の解説

- LET関数
    - 複数の変数を宣言し、それを基に計算を実行します
    - 変数は短縮名を使用して、シンプルに記述しています
- 変数定義
    - subArr (科目配列):
    ARRAY関数で、科目名を配列にします。
    科目名のフィールドコードが科目１～科目５であることを前提としています。
    - hrsArr (時間配列):
    同様に、各科目の時間数を配列化します。
    フィールドコードが時間数１～時間数５です。
    - dict (辞書):
    DIC()関数で空の辞書オブジェクトを作成します。後で科目と累積時間を紐付けるために使用します。
- ARRAY_MAPによる処理
    - 目的:
    時間数配列hrsArrを走査し、対応する科目名と時間数を累積して辞書dictに保存します。
    - 処理の流れ:
        - ARRAY_MAP(hrsArr, h, i, ...):
        配列hrsArrの各要素hとそのインデックスiを取得。
        - 内部のLET:
            - ARRAY_GET(subArr, i)で科目名を取得。
            - NVL(h, 0)で未入力を0に変換。
            - NVL(DIC_ITEM(dict, sbj), 0)で、辞書から以前の時間を取得（未登録なら0）。
            - 時間数が0より大きい場合、辞書に累積値を設定します。
        - 最終的に、全ての科目と時間数の累積が辞書に登録されます。
- 累積結果の文字列化
    - DIC_KEYS(dict):
    辞書dictに登録された全てのキー（科目名）を取得。
    - ARRAY_MAP:
    各キー（科目名）に対応する時間数を取得し、「科目名 X時間」という文字列を生成します。
    - JOIN:
    上記で生成した文字列をカンマ（,）で連結し、最終出力を完成させます。


# 計算式改訂版

dictionary で科目と時間を定義して、ループ処理。
こちらの方がわかりやすいかな。

```.js
// テーブル.まとめ SINGLE_LINE_TEXT
LET(
  arr, ARRAY( // 科目と時間の配列
    DIC("name", 科目１, "time", 時間１),
    DIC("name", 科目２, "time", 時間２),
    DIC("name", 科目３, "time", 時間３),
    DIC("name", 科目４, "time", 時間４),
    DIC("name", 科目５, "time", 時間５)
  ), 
  res, DIC(), // 集計用辞書
  tmp, ARRAY_MAP(arr, itm,
    LET(
      nm, NVL(DIC_ITEM(itm, "name"), "?"), // 科目名取得
      tm, NVL(DIC_ITEM(itm, "time"), 0), // 時間取得
      pv, NVL(DIC_ITEM(res, nm), 0), // 科目の累積時間
      IF(tm > 0, DIC_ITEM(res, nm, pv + tm)) // 時間を累計
    )
  ), // 配列処理終了
  JOIN(ARRAY_MAP(DIC_KEYS(res), key,
    key & " " & DIC_ITEM(res, key) // 出力形式
  ), ", ") // 結果を連結
)
```


# 計算式改訂版２

DIC_MAP 関数を使って、出力形式を作成します。
※ DIC_MAP 関数は、Ver.84 以降で利用できます。

```.js
// テーブル.まとめ SINGLE_LINE_TEXT
LET(
  arr, ARRAY( // 科目と時間の配列
    DIC("name", 科目１, "time", 時間１),
    DIC("name", 科目２, "time", 時間２),
    DIC("name", 科目３, "time", 時間３),
    DIC("name", 科目４, "time", 時間４),
    DIC("name", 科目５, "time", 時間５)
  ), 
  res, DIC(), // 集計用辞書
  tmp, ARRAY_MAP(arr, itm,
    LET(
      nm, NVL(DIC_ITEM(itm, "name"), "?"), // 科目名取得
      tm, NVL(DIC_ITEM(itm, "time"), 0), // 時間取得
      pv, NVL(DIC_ITEM(res, nm), 0), // 科目の累積時間
      IF(tm > 0, DIC_ITEM(res, nm, pv + tm)) // 時間を累計
    )
  ), // 配列処理終了
  JOIN(DIC_MAP(res, key, val,
    key & " " & val // 出力形式
  ), ", ") // 結果を連結
)
```