検証環境: 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 — UBound と LBound(サイズをベタ書きしない)
サイズを仮定せず、配列に尋ねましょう。
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始まり——
arr(1, 1)が左上のセルで、Option Baseに関係ありません。 - 単一セルは配列になりません。
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) で「インデックスが有効範囲にありません」 |
i が LBound..UBound の外 |
LBound(arr) To UBound(arr) でループ |
| 配列に空の区画が1つ多い | Dim a(10) が 0..10 = 11 区画を作った |
(1 To 10) で宣言 |
2次元配列で ReDim Preserve がエラー |
変えられるのは最後の次元だけ | 増える軸を最後に置くか転置 |
Range("A1").Value2 が配列でない |
単一セルはスカラーを返す | 複数セルの範囲を読む |
| 書き戻したデータがずれる | 書き込み範囲が arr と違うサイズ |
配列とまったく同じサイズの範囲に書く |
配列の配管作業をやめて、変換を伝える
配列は速いですが、ReDim Preserve・UBound(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) です。
