🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA 配列の使い方 — 宣言・ループ・範囲を100倍速く読む(7つの例)

|

Excel VBA 配列の使い方 — 宣言・ループ・範囲を100倍速く読む(7つの例)

検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-05

要点 — 配列は「多くの区画を持つ1つの変数」です。Excel VBA で最も効く一手は、範囲を丸ごと配列に読み込み、メモリ上で処理し、最後に一度だけ書き戻すこと——セルを1つずつ触るのではなく。

Sub 高速更新()
    Dim arr As Variant
    arr = Range("A2:C10000").Value2          ' 1回の読み込み -> 2次元配列

    Dim i As Long
    For i = 1 To UBound(arr, 1)
        arr(i, 3) = arr(i, 2) * 1.1          ' メモリ上で処理(一瞬)
    Next i

    Range("A2:C10000").Value2 = arr          ' 1回の書き込み
End Sub

1万行なら 約8秒と約0.1秒 の差です。本記事はこの1行と、その落とし穴へと積み上げていきます。

なぜ配列か——そして配列とは

普通の変数は1つの値を持ちます。配列は1つの名前のもとに値のリストを持ち、インデックスで取り出します。

Dim scores(1 To 3) As Long
scores(1) = 90
scores(2) = 75
scores(3) = 60

なぜ手間をかけるのか。速度と構造です。VBA がセルを読み書きするたびに、コードと Excel の間にある遅い境界を越えます。配列はメモリ上にあるので、1万区画のループは1万セルのループより何千倍も高速です。

例1 — 静的配列とインデックスの起点

静的配列は宣言時に決めた固定サイズを持ちます。推測しなくて済むよう、境界は明示しましょう。

Dim months(1 To 12) As String      ' インデックス 1..12 — 読みやすい
Dim zeroBased(0 To 9) As Double     ' インデックス 0..9

ヒント: 常に (n) ではなく (1 To n) と書きましょう。Dim a(10) は実は 11 区画(0〜10)を作ります(Option Base 1 を設定しない限り)。(1 To 10) と書けば疑いの余地がありません。

例2 — ReDim による動的配列

サイズが事前に分からないときは、空の配列を宣言し、後から ReDim でサイズを決めます。

Dim names() As String
Dim n As Long
n = Cells(Rows.Count, 1).End(xlUp).Row - 1   ' データ行数

ReDim names(1 To n)                          ' ここでサイズ決定
Dim i As Long
For i = 1 To n
    names(i) = Cells(i + 1, 1).Value
Next i

ただの ReDim は中身を消去します。既存の内容を残すには ReDim Preserve を使います。

例3 — ReDim Preserve(そして1つの大きな罠)

ReDim Preserve はデータを失わずにサイズを変えます。増えていくリストに最適です。

Dim hits() As String
Dim count As Long
count = 0

Dim cell As Range
For Each cell In Range("A2:A100")
    If cell.Value <> "" Then
        count = count + 1
        ReDim Preserve hits(1 To count)      ' 1つ増やし、残りは保持
        hits(count) = cell.Value
    End If
Next cell

罠: 2次元配列では、ReDim Preserve最後の次元しか変えられません。ReDim Preserve grid(1 To 5, 1 To 10)10 だけが変わるなら可ですが、5 を変えると 「インデックスが有効範囲にありません」 になります。回避策は、増える軸を最後の次元に置くか、転置することです。

例4 — UBoundLBound(サイズをベタ書きしない)

サイズを仮定せず、配列に尋ねましょう。

Dim arr As Variant
arr = Array("Mon", "Tue", "Wed")             ' 0始まりの配列

Dim i As Long
For i = LBound(arr) To UBound(arr)           ' 起点が何であれ動く
    Debug.Print arr(i)
Next i

範囲から作った2次元配列では、次元を渡します。UBound(arr, 1) が行数、UBound(arr, 2) が列数です。

例5 — 範囲を配列に読み込む(100倍速のコツ)

配列を学ぶ理由はこれに尽きます。範囲.Value2 は1回の読み込みで2次元・1始まりの配列を返します。

Sub 列を高速合計()
    Dim arr As Variant
    arr = Range("A2:C10000").Value2          ' arr(行, 列)、どちらも1始まり

    Dim total As Double, i As Long
    For i = 1 To UBound(arr, 1)
        total = total + arr(i, 2)            ' 2列目 = 数量
    Next i

    MsgBox "数量の合計: " & total
End Sub

覚えておくこと2つ:

  1. 結果は常に 1始まり——arr(1, 1) が左上のセルで、Option Base に関係ありません。
  2. 単一セルは配列になりませんRange("A1").Value2 は値そのものです。複数セルの範囲だけが2次元配列になります。

例6 — For Each で配列をループ

位置ではなく値だけが必要なら、For Each が最も読みやすいです。

Dim regions As Variant
regions = Array("North", "South", "East", "West")

Dim r As Variant
For Each r In regions
    Debug.Print r
Next r

例7 — Array()Split() で配列を素早く作る

代入を山ほど省く2つの一行コードです。

' Array() — 手早いリテラルのリスト(0始まり)
Dim days As Variant
days = Array("Mon", "Tue", "Wed", "Thu", "Fri")

' Split() — 区切り文字付きテキストを配列に(0始まり)
Dim parts As Variant
parts = Split("apple;banana;cherry", ";")
Debug.Print parts(0)        ' apple
Debug.Print UBound(parts)   ' 2  (3要素、0..2)

Join(parts, ", ") は逆——配列を文字列に戻します。

よくある配列のミス(と対処)

症状 原因 対処
arr(i) で「インデックスが有効範囲にありません」 iLBound..UBound の外 LBound(arr) To UBound(arr) でループ
配列に空の区画が1つ多い Dim a(10) が 0..10 = 11 区画を作った (1 To 10) で宣言
2次元配列で ReDim Preserve がエラー 変えられるのは最後の次元だけ 増える軸を最後に置くか転置
Range("A1").Value2 が配列でない 単一セルはスカラーを返す 複数セルの範囲を読む
書き戻したデータがずれる 書き込み範囲が arr と違うサイズ 配列とまったく同じサイズの範囲に書く

配列の配管作業をやめて、変換を伝える

配列は速いですが、ReDim PreserveUBound(arr, 2)・1始まり対0始まりの管理は、5分の作業を半日に変える類の細部です。ExcelMaster Agent なら目的を伝えるだけ——「表全体を読み込んで、すべての単価を10%上げて、書き戻して」——範囲を配列に読む→処理→書き戻すパターンを、境界も含めて正しく生成します。無料で試す →

関連記事

よくある質問

VBA で配列は何をするもの? 配列は同じ種類の値を1つの名前のもとにまとめて格納し、インデックス(arr(1)arr(2)…)で取り出します。データのリストをメモリ上で読み・処理でき、同じデータをセル単位で読むよりはるかに高速です。

Excel VBA で範囲の代わりに配列を使うには? 範囲を一度で配列に読み込み——arr = Range("A1:C10000").Value2——UBound でループし、Range(...).Value2 = arr で書き戻します。何千回もの遅いセル操作が、1回の読みと1回の書きに置き換わります。

ReDim と ReDim Preserve の違いは? ReDim は動的配列のサイズを変え、中身を消去します。ReDim Preserve はサイズを変えつつ値を保持します——ただし2次元配列では最後の次元しか変えられません。

なぜ私の VBA 配列は0始まりなの? Array()Split() から作る配列は既定でインデックス0から始まります(Option Base 1 がなければ)。範囲から .Value2 で読む配列は常に1始まりです。LBound(arr) To UBound(arr) でループすれば起点は関係なくなります。

VBA 配列の長さを取得するには? UBound(arr) - LBound(arr) + 1 を使います。範囲から作った2次元配列では、行数は UBound(arr, 1)、列数は UBound(arr, 2) です。