配列の添え字取得ヘルパー:TableBounds
前回は、配列操作を「Where」と「PickRows」に分解する設計を紹介しました。
VBA配列攻略1:配列フィルタの設計を考える
配列に軸足を置いて実装を進めるため、WhereとPickRows 実装の前に「配列を表として扱うための基盤」を作ります。本ライブラリでは、配列を「1行目にヘッダーを持つ表(テーブル)」として扱います。
今回は表を構造として扱うための最初の一歩としてTableBoundsを作成します。
VBAで配列を扱う際、常に付きまとうのが LBound と UBound です。
For r = LBound(vData, 1) To UBound(vData, 1)
For c = LBound(vData, 2) To UBound(vData, 2)
' 処理
Next c
Next r
ReDim vNewArray(1 To UBound(vData, 1) - LBound(vData, 1) + 1, _
1 To UBound(vData, 2) - LBound(vData, 2) + 1)
これから作るTableBounds構造体を使うと、コードは以下のように変わります。
' 入力候補(インテリセンス)が出るため負荷が下がる。
Dim tr As TableBounds
tr = GetTableBounds(vData)
With tr
For r = .FirstRow To .LastRow
For c = .FirstCol To .LastCol
' 処理
Next c
Next r
End With
Dim tr As TableBounds
tr = GetTableBounds(vData)
ReDim vNewArray(1 To tr.RowCount, 1 To tr.ColCount)
LBound(vData, 2) とキー入力するのに比べ、ドットを打った後に次の入力候補が出ることで思考が途切れにくくなります。最初、最後、いくつ、という配列の範囲管理をTableBoundsに任せることで、ロジックに意識を向けやすくなります。
「第2引数の 1 は行だっけ、列だっけ?」「UBound - LBound の後は +1 が必要だっけ?」。こうした「思い出す手間」や「打ち間違えミスによるバグ」も減るでしょう。
実装コード
以下は2次元配列用サンプルです。1次元配列用を作るときは標準モジュールを分けると良いでしょう。
コードは解説用のサンプルであり、実務利用は自己責任でお願いします。
'--- 構造体:表形式の配列情報を保持する ---
Public Type TableBounds
FirstRow As Long
LastRow As Long
RowCount As Long
FirstCol As Long
LastCol As Long
ColCount As Long
End Type
'--- 関数:配列を解析してTableBounds構造体を返す ---
Public Function GetTableBounds(ByRef vData As Variant) As TableBounds
Dim tr As TableBounds
' ガード句:配列でない場合は空のまま返す(早期リターン)
If Not IsArray(vData) Then Exit Function
' 二次元配列であることを前提にインデックスを取得
' ※一次元配列の可能性がある場合は別途エラーハンドリングが必要
On Error Resume Next
With tr
.FirstRow = LBound(vData, 1)
.LastRow = UBound(vData, 1)
.RowCount = .LastRow - .FirstRow + 1
.FirstCol = LBound(vData, 2)
.LastCol = UBound(vData, 2)
.ColCount = .LastCol - .FirstCol + 1
End With
On Error GoTo 0
GetTableBounds = tr
End Function
これを構造体でなくクラスに配列ごと閉じ込めることもできます。より多くの機能を付けやすくなります。(例:data.RowCount data.GetHeader)クラスについては別途予定しています。
次回は「条件に合う行番号を取得するWhereメソッド」を実装していきます。