初投稿です。GAS(Google Apps Script)とVBAを用いた業務効率化をやっております!
はじめに
GASでは頻出の 「配列に配列をPushしていく」 という処理※が、VBAではそのまま使えませんでした。
GASでは当たり前だったこと
GASでは、スプレッドシートAPIの呼び出し回数が処理速度に直結します。そのため、API呼び出しを極力減らすことが重要になります。
そこで一般的だったのが、1次元配列を push してデータを集め、最後に2次元配列としてまとめて書き戻す という方法です。これはI/Oの観点で 強く推奨される、最もシンプルな設計でした。
⇒せいろそばを1枚ずつおかわりして積んでいく イメージです。
1枚(1行)ずつ完成したものを、下にどんどん追加していきます。
const rows = [];
rows.push(["A", 100, "OK"]);
rows.push(["B", 200, "NG"]);
rows.push(["C", 300, "OK"]);
console.log(rows);
// [ ["A",100,"OK"], ["B",200,"NG"], ["C",300,"OK"] ]
VBAで同じことをやろうとして詰んだ話
同じ感覚で、VBAでも2次元配列に行を追加しようとしました。
' 2次元配列に行を追加しようとしたコード
Dim result() As Variant
ReDim result(1 To 1, 1 To 3)
' 1行目は普通に代入できる
result(1, 1) = "A"
result(1, 2) = 100
result(1, 3) = "OK"
' 2行目を追加したいが…
' ↓ こうしたい気持ちはある
'ReDim Preserve result(1 To 2, 1 To 3) ' 行方向は拡張できない
ところがVBAには、配列に対して行を push するための仕組みがありません。
仮の配列に対して、GASの push に相当する操作が存在しないのです。
⇒おかわり厳禁でした。
なぜVBAでは行のPushができないのか
これは単なるバグや制約ではなく、VBAの仕様です。
VBAの標準配列では、後からサイズを変更できるのは最後の次元(列方向)のみで、行方向に広げることはできません。
arr(行, 列)
列 → 1 2 3
行1 A 100 OK
行2 B 200 NG
行3 C 300 OK
👉 行は増やせず、列だけ増やせます。初見では驚くポイントです。
実務的には行を増やしたい
業務データでは、
- 列 = 属性(例:商品名・金額・ステータス)
- 行 = レコード(例:1件の注文・1人のユーザー)
という構造が一般的です。
つまり、ユースケースとして圧倒的に多いのは 行(レコード)の追加 ですが、VBAの標準配列ではこれが直接サポートされていません。
回避方法:Collection of 配列
そこで実務的な回避策としてよく使われるのが、Collectionを使う方法です。
1行分のデータを一次元配列として作り、それをCollectionに追加していきます。
Dim rows As New Collection
rows.Add Array("A", 100, "OK")
rows.Add Array("B", 200, "NG")
rows(1)(2) ' → 100
この方法であれば、行を柔軟に追加できます。
Collection of Dictionary について
※ 行をDictionaryとして扱う方法もありますが、RC参照ができないため、本記事では説明を省きます。
Transpose について
Transpose を使って回避する考え方もありますが、配列の向きを常に意識する必要があり、可読性が下がりやすいため、本記事では詳細な説明は省きます。
配列は最後だけ使う
VBAでは、配列は 最終的にExcelに書き戻すための器 と割り切るのが実務的です。
ReDim result(1 To rows.Count, 1 To 3)
For r = 1 To rows.Count
For c = 1 To 3
result(r, c) = rows(r)(c)
Next c
Next r
Sheet1.Range("A1").Resize(rows.Count, 3).Value = result
👉 配列は 完成したデータを一気に渡す箱 として使います。
まとめ
- VBAの2次元配列は行を
pushできない - これは仕様であり回避不可
- 行を集める処理にはCollectionを使う
- 配列は入出力専用と割り切ると楽になる