0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VBA配列攻略2:L/UBound を FirstRow/LastRow に置き換えて、コードでなくロジックに集中する

0
Posted at

配列の添え字取得ヘルパー:TableBounds

前回は、配列操作を「Where」と「PickRows」に分解する設計を紹介しました。
VBA配列攻略1:配列フィルタの設計を考える
配列に軸足を置いて実装を進めるため、WherePickRows 実装の前に「配列を表として扱うための基盤」を作ります。本ライブラリでは、配列を「1行目にヘッダーを持つ表(テーブル)」として扱います。
今回は表を構造として扱うための最初の一歩としてTableBoundsを作成します。

VBAで配列を扱う際、常に付きまとうのが LBoundUBound です。

ループ事例(変更前)
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メソッド」を実装していきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?