ExcelVBAで表形式のデータを扱っていると、「1次元配列だけでは行と列の情報を管理しきれない」と感じる場面が出てきます。そんなときに便利なのが2次元配列(多次元配列)です。
この記事では、2次元配列の宣言方法から、セル範囲(Range)と配列を一括変換するテクニック、行数・列数が異なる「ジャグ配列」の代用方法まで、実務でそのまま使えるコード例を交えて解説します。
2次元配列とは何か
1次元配列が「1列のリスト」だとすると、2次元配列は「行×列の表」をそのままメモリ上に持てるデータ構造です。Excelのセル範囲は本質的に「行×列」の表なので、2次元配列と非常に相性が良いのが特徴です。
Sub Sample2DArray()
Dim arr(1 To 3, 1 To 2) As String
arr(1, 1) = "田中": arr(1, 2) = "営業部"
arr(2, 1) = "佐藤": arr(2, 2) = "経理部"
arr(3, 1) = "鈴木": arr(3, 2) = "開発部"
Dim i As Long
For i = 1 To 3
Debug.Print arr(i, 1) & " / " & arr(i, 2)
Next i
End Sub
Dim arr(1 To 3, 1 To 2) のように、カンマ区切りで2つの次元を指定します。1つ目が「行」、2つ目が「列」に対応すると考えると、セル範囲との対応関係がイメージしやすくなります。
Range⇔配列の一括変換
2次元配列が最も威力を発揮するのが、セル範囲との一括変換です。セルを1つずつループで読み書きするより、配列に一括変換してから処理するほうが圧倒的に高速です。
セル範囲を配列に読み込む
Sub RangeToArray()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim dataArr As Variant
dataArr = ws.Range("A1:C100").Value
' dataArr(1, 1) が A1、dataArr(1, 2) が B1 に対応する
Dim i As Long
For i = 1 To UBound(dataArr, 1)
If dataArr(i, 1) <> "" Then
Debug.Print dataArr(i, 1) & " : " & dataArr(i, 3)
End If
Next i
End Sub
Range.Value を Variant 型の変数に代入するだけで、自動的に2次元配列に変換されます。UBound(dataArr, 1) は行数の上限、UBound(dataArr, 2) は列数の上限を取得します。
配列をセル範囲に書き戻す
Sub ArrayToRange()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet2")
Dim resultArr(1 To 5, 1 To 2) As Variant
Dim i As Long
For i = 1 To 5
resultArr(i, 1) = "商品" & i
resultArr(i, 2) = i * 1000
Next i
ws.Range("A1:B5").Value = resultArr
End Sub
配列のサイズとセル範囲のサイズ(行数・列数)を一致させておく必要がある点に注意してください。サイズが一致しないとエラーになったり、意図しない範囲にデータが入ったりします。
動的な2次元配列とReDim Preserve
行数が実行時にしか分からない場合は、動的配列を使います。ただし2次元配列で ReDim Preserve を使う際は、最後の次元しかサイズ変更できないという制約があるため注意が必要です。
Sub DynamicArrayCaution()
Dim arr() As Variant
ReDim arr(1 To 10, 1 To 3)
' OK:最後の次元(列側)は変更できる
ReDim Preserve arr(1 To 10, 1 To 5)
' NG:最初の次元(行側)を変更しようとするとエラーになる
' ReDim Preserve arr(1 To 20, 1 To 5)
End Sub
行数も可変にしたい場合は、あらかじめ最大件数で配列を確保しておき、使わない部分は無視する方法や、Collectionやコレクションを併用する方法が現実的です。
Sub CountBeforeRedim()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim arr() As Variant
ReDim arr(1 To lastRow, 1 To 3)
Dim i As Long
For i = 1 To lastRow
arr(i, 1) = ws.Cells(i, "A").Value
arr(i, 2) = ws.Cells(i, "B").Value
arr(i, 3) = ws.Cells(i, "C").Value
Next i
End Sub
先に最終行を取得してから配列サイズを確定させることで、ReDim Preserve の制約を回避できます。
ジャグ配列(配列の配列)の代用方法
VBAには他言語のような「ジャグ配列(各行の要素数が異なる配列)」を直接宣言する構文がありません。しかし、配列の中にVariant型の配列を入れることで同じことが実現できます。
Sub JaggedArraySample()
Dim jagged(1 To 3) As Variant
jagged(1) = Array("A", "B")
jagged(2) = Array("C", "D", "E", "F")
jagged(3) = Array("G")
Dim i As Long, j As Long
For i = 1 To 3
For j = LBound(jagged(i)) To UBound(jagged(i))
Debug.Print "行" & i & ": " & jagged(i)(j)
Next j
Next i
End Sub
jagged(i) に1次元配列を格納し、jagged(i)(j) の形で内側の要素にアクセスします。行ごとに項目数がバラバラな集計結果などを扱うときに便利なテクニックです。
実践例:2次元配列で高速に重複チェックする
最後に、2次元配列とDictionaryを組み合わせて、大量データの重複チェックを高速に行う例を紹介します。
Sub FastDuplicateCheck()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim dataArr As Variant
dataArr = ws.Range("A1:B" & lastRow).Value
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 1 To UBound(dataArr, 1)
Dim key As String
key = dataArr(i, 1)
If dict.Exists(key) Then
dataArr(i, 2) = "重複"
Else
dict.Add key, True
dataArr(i, 2) = "OK"
End If
Next i
ws.Range("A1:B" & lastRow).Value = dataArr
End Sub
セルを1つずつ読み書きせず、配列上で判定処理を完結させてから最後に一括で書き戻すことで、数万行規模のデータでも高速に処理できます。
まとめ
2次元配列は、Excelのセル範囲を扱ううえで非常に相性の良いデータ構造です。
Dim arr(1 To 行数, 1 To 列数)で宣言し、arr(行, 列)でアクセスするRange.Valueへの代入・取得で、セル範囲と2次元配列を一括変換できるReDim Preserveは最後の次元しかサイズ変更できないため、行数は事前に確定させる- 行ごとの要素数が異なる場合は、配列の中に配列を入れる「ジャグ配列」の代用テクニックが使える
セルを1件ずつループする処理を2次元配列に置き換えるだけで、マクロの実行速度が大きく改善することがあります。ぜひ実務のコードにも取り入れてみてください。


コメント