VBAの配列(Array)の基本と使い方|静的・動的・2次元配列で処理を高速化する

VBAの配列を使うと、セルへのアクセス回数を最小限に抑えられるため、1万行のデータでも数秒で処理できます。基本は「シートから配列に読み込む→配列上で処理→シートに一括書き戻す」の3ステップです。

この記事では、次の内容を順番に解説します。

  • 配列の基本と宣言方法(静的・動的)
  • Array関数で配列を作る方法
  • セル範囲を配列に読み込んで処理する方法
  • 2次元配列の扱い方
  • 配列を使った処理速度の改善例

配列とは何かを理解するには?

配列は複数の値を1つの変数でまとめて管理する仕組みです。たとえば5人分の名前を管理する場合、通常の変数なら5つ必要ですが、配列なら1つで済みます。

' 通常の変数:5つ必要
Dim name1 As String
Dim name2 As String
Dim name3 As String
Dim name4 As String
Dim name5 As String

' 配列:1つで5つ分をまとめて管理
Dim names(1 To 5) As String

配列の各要素には番号(インデックス)でアクセスします。

names(1) = "田中"
names(2) = "鈴木"
names(3) = "佐藤"

MsgBox names(2)  ' → 「鈴木」が表示される

配列を宣言するには?(静的配列)

サイズが決まっている場合は、宣言時に要素数を指定します。これを「静的配列」といいます。

' 書き方①:0始まり(要素数5:0〜4)
Dim scores(4) As Long

' 書き方②:1始まりで明示(要素数5:1〜5)
Dim scores(1 To 5) As Long

' 値の代入
scores(1) = 80
scores(2) = 95
scores(3) = 70

VBAはデフォルトで0始まりですが、Option Base 1 をモジュールの先頭に書くと1始まりになります。混乱を避けるため、(1 To 5) のように明示的に書くのが安全です。

サイズが決まらない配列を使うには?(動的配列)

データ件数が実行時まで分からない場合は、動的配列を使います。ReDim でサイズを後から指定できます。

Sub DynamicArraySample()
    Dim ws      As Worksheet
    Dim lastRow As Long
    Dim arr()   As String  ' サイズを指定せずに宣言
    Dim i       As Long

    Set ws = ThisWorkbook.Sheets("Sheet1")
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

    ' 実行時にサイズを決める
    ReDim arr(1 To lastRow - 1)  ' 2行目〜最終行の件数分

    For i = 1 To lastRow - 1
        arr(i) = ws.Cells(i + 1, 1).Value
    Next i

    MsgBox "取得件数:" & UBound(arr)
End Sub

ReDim Preserveについて:すでに値が入っている配列のサイズを変更するとき、ReDim だけだと中身がリセットされます。中身を保持したままサイズを変えたい場合は ReDim Preserve を使います。ただし、最後の次元のサイズしか変更できません。

ReDim Preserve arr(1 To lastRow)  ' 中身を保持しながらサイズを拡張

Array関数で配列を作るには?

固定の値をまとめて配列にしたい場合は Array 関数が便利です。

' 月名の配列を作る
Dim months As Variant
months = Array("1月", "2月", "3月", "4月", "5月", "6月", _
               "7月", "8月", "9月", "10月", "11月", "12月")

MsgBox months(0)   ' → 「1月」(Array関数は0始まり)
MsgBox months(11)  ' → 「12月」

For Eachと組み合わせると、固定リストを順番に処理できます。

' 対象シート名のリストをArray関数で作り、ループ処理する
Dim sheetNames As Variant
Dim sName      As Variant
sheetNames = Array("1月", "2月", "3月")

For Each sName In sheetNames
    ThisWorkbook.Sheets(sName).Range("A1").Value = "処理済"
Next sName

セル範囲を配列に読み込んで高速処理するには?

VBAが遅くなる最大の原因は「セルへの繰り返しアクセス」です。セルを1行ずつ読み書きするのではなく、まとめて配列に読み込んでから処理し、最後に一括で書き戻すことで大幅に高速化できます。

遅い書き方(セルに1行ずつアクセス):

Dim i As Long
For i = 1 To 10000
    If Cells(i, 1).Value = "OK" Then
        Cells(i, 2).Value = "済"
    End If
Next i

速い書き方(配列に読み込んで一括処理):

Sub FastProcess()
    Dim dataArr As Variant
    Dim i       As Long

    ' A列・B列をまとめて配列に読み込む
    dataArr = Range("A1:B10000").Value

    ' 配列上で処理(セルにはアクセスしない)
    For i = 1 To UBound(dataArr, 1)
        If dataArr(i, 1) = "OK" Then
            dataArr(i, 2) = "済"
        End If
    Next i

    ' 処理済み配列をシートに一括書き戻す
    Range("A1:B10000").Value = dataArr
End Sub

この方法では、シートへのアクセスが「読み込み1回」と「書き戻し1回」の合計2回だけになります。セルに1行ずつアクセスする方法と比べると、数十〜数百倍の速度差が出ることもあります。

2次元配列を扱うには?

Range.Value で複数列を読み込むと、自動的に2次元配列になります。配列名(行, 列) の順でアクセスします。

Sub TwoDimArray()
    Dim arr     As Variant
    Dim i       As Long
    Dim rowCount As Long
    Dim colCount As Long

    ' A1:C5を配列に読み込む(5行3列の2次元配列)
    arr = Range("A1:C5").Value

    rowCount = UBound(arr, 1)  ' 行数(第1次元)
    colCount = UBound(arr, 2)  ' 列数(第2次元)

    Debug.Print "行数:" & rowCount  ' → 5
    Debug.Print "列数:" & colCount  ' → 3

    ' 2行目・3列目(C2セルの値)を取得
    Debug.Print arr(2, 3)
End Sub

注意:Range.Value で読み込んだ2次元配列は、1列のみ(例:Range(“A1:A100”))の場合でも arr(i, 1) のように列インデックスが必要です。arr(i) だけではエラーになります。

UBoundとLBoundの使い方

配列のサイズを調べるには UBound(最大インデックス)と LBound(最小インデックス)を使います。

Dim arr As Variant
arr = Range("A1:A100").Value

Debug.Print LBound(arr, 1)  ' → 1(行の最小インデックス)
Debug.Print UBound(arr, 1)  ' → 100(行の最大インデックス)
Debug.Print UBound(arr, 2)  ' → 1(列の最大インデックス)

' ループでよく使う書き方
Dim i As Long
For i = LBound(arr, 1) To UBound(arr, 1)
    Debug.Print arr(i, 1)
Next i

まとめ

  • 静的配列Dim arr(1 To 5) As String のようにサイズを固定して宣言する。
  • 動的配列Dim arr() As String で宣言し、ReDim で後からサイズを指定。中身を保持するなら ReDim Preserve
  • Array関数:固定リストをまとめて配列にしたいときに便利。0始まりになる点に注意。
  • Range.Valueで一括読み込み:セルへのアクセスを「読み込み1回・書き戻し1回」に減らして高速化する。
  • 2次元配列arr(行, 列) でアクセス。1列のみでも列インデックスが必要。
  • UBound / LBound:配列のサイズを動的に取得してループに使う。

よくある質問

配列はいつ使うべきですか?普通のループとどう使い分ければいいですか?

処理する行数が1000行を超えるような場合や、同じセルを何度も読み書きする処理は配列を使うと効果的です。数十行程度のシンプルな処理であれば通常のループで十分です。「遅い」と感じたときに配列への切り替えを検討するのが現実的です。

Range.Valueで読み込んだ配列の列数はどうやって確認しますか?

UBound(arr, 2) で確認できます。arr, 1 が行数(第1次元)、arr, 2 が列数(第2次元)です。例えば Range("A1:D100").Value で読み込んだ場合、UBound(arr, 1) = 100UBound(arr, 2) = 4 になります。

配列をシートに書き戻すときにサイズが合わないとどうなりますか?

書き戻す範囲と配列のサイズが一致しないとエラーになります。読み込んだ範囲と同じサイズの範囲を指定して書き戻すのが安全です。または、左上のセルだけ指定して Range("A1").Resize(UBound(arr,1), UBound(arr,2)).Value = arr のように書くと、配列のサイズに合わせて自動的に範囲を調整できます。

配列の中身を初期化(リセット)するにはどうすればいいですか?

Erase arr で配列の中身を初期化できます。数値型の要素は0に、文字列型は空文字になります。動的配列の場合は Erase を実行するとサイズも解放されるため、再度 ReDim が必要になります。

配列を使っても処理が速くならないことがありますか?

あります。ScreenUpdating = FalseCalculation = xlCalculationManual を設定していない場合、セルへの書き戻し時に画面更新や再計算が走って遅くなることがあります。配列と合わせてこれらの設定も行うと最大限の速度が出ます。また、配列の要素数が非常に大きい場合はメモリ不足になることもあります。


動画で学びたい方へ

「記事を読んでも、実際に自分で書けるか不安…」という方には、動画で基礎からじっくり学べる講座がおすすめです。

VBAが初めての方を前提に、つまずきやすいポイントを先回りして解説しています。サンプル動画は無料でご覧いただけます。

動画で学ぶExcelマクロ|JIMOVEオンラインスクール

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール