【この記事について】この記事のコードは、Windows 11 の Excel(バージョン 16.0/ビルド 20326・64ビット)で2026年9月26日に実際に実行し、表示される結果とエラー番号を確かめたものです。処理時間はパソコンの性能や Excel の設定で変わるため、目安として読んでください。
VBAの配列は、同じ種類のデータを「番号つきの箱の列」にまとめて入れる仕組みです。Dim 名前(2) と書くと 0・1・2 の3つの箱ができ、For と UBound で順番に取り出せます。さらにセル範囲を Range("A2:D6").Value で配列へ一度に読み込めば、セルを1つずつ触るより大幅に速くなります。筆者の環境では2万行の処理が約1.0秒から約0.05秒に縮みました。この記事では、配列の作り方から、よく出るエラー3つの直し方まで、実行して確かめたコードで順に説明します。

配列とは「番号つきの箱」を一列に並べたもの
ふつうの変数は、箱が1つだけです。担当者が4人いれば変数を4つ作ることになり、人数が増えるたびにコードを書き足さなければなりません。
配列なら、1つの名前の下に箱をいくつも並べ、番号(添字)で区別できます。「3番目の人」は members(2) のように書きます。番号で指定できるので、For で「0番から最後まで」を順に処理でき、人数が増えてもコードはそのままで済みます。
最初に覚えておきたいのは次の3点です。
- 番号はふつう 0 から始まる(
Dim fruits(2)は 0・1・2 の3つ) - 最初の番号は
LBound、最後の番号はUBoundで調べられる - セル範囲から読み込んだ配列だけは 1 から始まる(後で説明します)
基本1:大きさを決めて作る(Dim と For)
入れる数が決まっているときは、Dim で大きさを指定して作ります。( ) の中に書くのは「個数」ではなく「最後の番号」です。ここが最初のつまずきどころです。
Sub Sample1_StaticArray()
Dim fruits(2) As String ' 0~2 の3つ分の箱ができる
Dim i As Long
fruits(0) = "りんご"
fruits(1) = "みかん"
fruits(2) = "ぶどう"
For i = 0 To 2
Debug.Print i & ": " & fruits(i)
Next i
End Sub
イミディエイトウィンドウ(Ctrl+G で開きます)には、次のように表示されます。
0: りんご
1: みかん
2: ぶどう
Dim fruits(2) で箱は3つです。「3つ欲しいから 3 と書く」と箱は4つになり、最後の1つが空のまま残ります。
基本2:Array 関数でまとめて作る(LBound・UBound)
中身が最初から決まっているなら、Array 関数で1行にまとめられます。このとき、変数は Variant 型で宣言します。
Sub Sample2_ArrayFunction()
Dim members As Variant
Dim i As Long
members = Array("佐藤", "鈴木", "高橋", "田中")
For i = LBound(members) To UBound(members)
Debug.Print i & ": " & members(i)
Next i
Debug.Print "件数: " & (UBound(members) - LBound(members) + 1)
End Sub
0: 佐藤
1: 鈴木
2: 高橋
3: 田中
件数: 4
ループの範囲を 0 To 3 と数字で書かず、LBound(members) To UBound(members) と書くのがコツです。あとで人数を足しても、ループの範囲を直す必要がありません。件数は UBound − LBound + 1 で求めます。
基本3:あとから広げる(ReDim Preserve)
「条件に合う人だけ集めたい」のように、いくつ入るか実行するまで分からないときは、大きさを決めずに Dim names() As String と宣言し、必要になったら ReDim で広げます。
次のコードは、A列に担当者、B列に件数が入った表(2〜6行目)から、件数が100以上の人だけを集めます。
Sub Sample3_ReDimPreserve()
Dim names() As String
Dim cnt As Long
Dim r As Long
cnt = 0
For r = 2 To 6
If Cells(r, 2).Value >= 100 Then
ReDim Preserve names(cnt) ' 1つ広げる(中身は残す)
names(cnt) = Cells(r, 1).Value
cnt = cnt + 1
End If
Next r
If cnt = 0 Then
Debug.Print "該当なし"
Else
Debug.Print cnt & "人: " & Join(names, "、")
End If
End Sub
B列が「120・80・150・99・100」のとき、結果は次のとおりでした。
3人: 佐藤、高橋、伊藤
ポイントは Preserve です。Preserve を付けずに ReDim すると、それまで入れた中身が消えて空に戻ります。また、1人も該当しなかったときは ReDim が一度も実行されず、配列の大きさが決まっていない状態のままです。その状態で Join や UBound を使うとエラーになるため、先に cnt = 0 かどうかを確かめています(全員を100未満にして実行し、「該当なし」と出ることも確認しました)。
本命:セル範囲を配列へ一度に読み込む
実務で配列がいちばん役に立つのは、ここです。変数 = Range("A2:D6").Value の1行で、表がまるごと配列に入ります。
次のコードは、A列に品名、B列に単価、C列に数量が入った5行の表について、D列に金額(単価×数量)を計算して書き戻します。
Sub Sample4_RangeToArray()
Dim data As Variant
Dim r As Long
data = Range("A2:D6").Value ' 5行×4列が一度に入る
Debug.Print "行: " & LBound(data, 1) & "~" & UBound(data, 1) & _
" / 列: " & LBound(data, 2) & "~" & UBound(data, 2)
For r = 1 To UBound(data, 1)
data(r, 4) = data(r, 2) * data(r, 3) ' D列 = 単価 × 数量
Next r
Range("A2:D6").Value = data ' まとめて書き戻す
End Sub
行: 1~5 / 列: 1~4
表示を見ると分かるとおり、セル範囲から作った配列は「行・列」の2次元で、番号は 1 から始まります。data(1, 1) が範囲の左上(ここでは A2)です。Dim や Array で作った配列は 0 始まりなので、ここだけ番号の数え方が違います。
計算は配列の中で済ませ、最後に Range("A2:D6").Value = data で一度に書き戻します。実行すると、D列には 1200・900・1000・1080・600 が入りました。
どれくらい速くなるのか(2万行で実測)
A列に1〜20000の数字を入れ、B列にその2倍を書く処理を、セルを1つずつ扱う書き方と配列の書き方で比べました。
Sub Speed_Cell()
Dim r As Long
For r = 1 To 20000
Cells(r, 2).Value = Cells(r, 1).Value * 2
Next r
End Sub
Sub Speed_Array()
Dim data As Variant
Dim r As Long
data = Range("A1:B20000").Value
For r = 1 To 20000
data(r, 2) = data(r, 1) * 2
Next r
Range("A1:B20000").Value = data
End Sub
Sub MeasureSpeed()
Dim t As Double
t = Timer
Speed_Cell
Debug.Print "セル1つずつ: " & Format(Timer - t, "0.00") & " 秒"
t = Timer
Speed_Array
Debug.Print "配列でまとめて: " & Format(Timer - t, "0.00") & " 秒"
End Sub
3回実行した結果は次のとおりです(Excel を非表示で自動実行、画面更新オン、計算方法は「自動」)。
| 回 | セル1つずつ | 配列でまとめて |
|---|---|---|
| 1回目 | 1.04 秒 | 0.05 秒 |
| 2回目 | 0.99 秒 | 0.04 秒 |
| 3回目 | 1.08 秒 | 0.04 秒 |
どちらの書き方でも、B列の結果(1行目が2、20000行目が40000)が同じになることを確かめています。20倍以上の差が出たのは、セルの読み書きのたびに Excel 本体とのやり取りが発生するためです。配列の書き方なら、そのやり取りは「読み込み1回・書き戻し1回」で済みます。処理が遅いマクロは、まずループの中で Cells を触っていないかを見直してみてください。
文字列を分ける・つなぐ(Split と Join)
カンマ区切りの文字を配列に分けるのが Split、配列を1つの文字列につなぐのが Join です。
Sub Sample5_SplitJoin()
Dim parts As Variant
parts = Split("東京,大阪,名古屋", ",")
Debug.Print (UBound(parts) + 1) & "個: " & parts(0) & " / " & parts(2)
Debug.Print Join(parts, "→")
End Sub
3個: 東京 / 名古屋
東京→大阪→名古屋
Split で作った配列も 0 始まりです。3つに分けたときの最後は parts(2) で、parts(3) ではありません。
よく出るエラー3つと直し方
配列でつまずく原因は、ほとんどが次の3つです。どれも実際に実行して、表示されるエラー番号を確かめました。
エラー9「インデックスが有効範囲にありません」
いちばん多いエラーです。存在しない番号の箱を指定したときに出ます。
Sub Error1_OutOfRange()
Dim scores(2) As Long ' 使えるのは 0, 1, 2 だけ
scores(3) = 80 ' ← ここで実行時エラー9
End Sub
Dim scores(2) で作った箱は 0〜2 なので、scores(3) はありません。大きさを決めていない配列に UBound を使った場合も、同じエラー9になります。
Sub Error2_NotAllocated()
Dim names() As String ' まだ大きさが決まっていない
Debug.Print UBound(names) ' ← ここで実行時エラー9
End Sub
直し方は、ループの範囲を LBound〜UBound にすることと、ReDim する前に配列を使わないことです。「基本3」のコードで件数を数えていたのは、この2つ目のエラーを避けるためです。エラー9は配列以外(シート名の間違いなど)でも出ます。原因の切り分けは、次の記事で詳しく説明しています。

ReDim Preserve で広げられるのは「最後の次元」だけ
行と列を持つ2次元の配列を Preserve 付きで広げるとき、広げられるのは最後の次元(列のほう)だけです。1次元目を広げようとすると、エラー9で止まります。
Sub Error3_PreserveFirstDim()
Dim table() As Variant
ReDim table(1 To 2, 1 To 3)
ReDim Preserve table(1 To 3, 1 To 3) ' ← 1次元目は広げられない(エラー9)
End Sub
行を増やしたい表は、最初から十分な大きさで ReDim しておくか、「実務例」のように件数を数え終わってから一度だけ ReDim するのが確実です。
エラー13「型が一致しません」(1セルだけ読み込んだとき)
セル範囲を配列へ読み込むコードは、範囲が1セルだけだと配列になりません。中身はただの値になり、UBound を使うとエラー13で止まります。データが1件しかない日だけ止まるマクロは、たいていこれが原因です。
Sub Error4_SingleCell()
Dim data As Variant
data = Range("A2:A2").Value ' 1セルだけだと配列にならない
Debug.Print UBound(data, 1) ' ← ここで実行時エラー13
End Sub
IsArray で配列かどうかを確かめ、配列でなければ1行1列の配列に包み直すと、後ろの処理を変えずに済みます。
Sub Fix4_SingleCell()
Dim data As Variant
data = Range("A2:A2").Value
If Not IsArray(data) Then
Dim tmp(1 To 1, 1 To 1) As Variant
tmp(1, 1) = data
data = tmp ' 1行1列の配列に包み直す
End If
Debug.Print "行数: " & UBound(data, 1) & " / 値: " & data(1, 1)
End Sub
行数: 1 / 値: 佐藤
実務例:担当者ごとの売上合計を一度に出す
最後に、ここまでの内容を組み合わせた例です。A列に担当者、B列に金額が並んだ明細から、担当者ごとの合計をD・E列に書き出します。明細の最終行は自動で調べます。
Sub Sample7_TotalByPerson()
Dim data As Variant
Dim result() As Variant
Dim dic As Object
Dim lastRow As Long, r As Long, i As Long
Dim k As Variant
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
data = Range("A2:B" & lastRow).Value ' 明細を配列へ
Set dic = CreateObject("Scripting.Dictionary")
For r = 1 To UBound(data, 1)
dic(data(r, 1)) = dic(data(r, 1)) + data(r, 2) ' 担当者ごとに足す
Next r
ReDim result(1 To dic.Count, 1 To 2) ' 担当者の人数ぶんの表
i = 0
For Each k In dic.Keys
i = i + 1
result(i, 1) = k
result(i, 2) = dic(k)
Next k
Range("D1:E1").Value = Array("担当者", "合計")
Range("D2").Resize(dic.Count, 2).Value = result ' 一度に書き出す
End Sub
明細が「佐藤 12000・鈴木 8000・佐藤 5000・高橋 15000・鈴木 3000・佐藤 7000・高橋 2000」の7行のとき、D・E列には次のように出ました。
| 担当者 | 合計 |
|---|---|
| 佐藤 | 24000 |
| 鈴木 | 11000 |
| 高橋 | 17000 |
明細の読み込みも、結果の書き出しも1回ずつです。担当者ごとの足し算には Dictionary(名前をキーにして値をためる入れ物)を使い、人数が確定してから ReDim result(1 To dic.Count, 1 To 2) で表を1回だけ作っています。最終行の取り方は、次の記事で詳しく説明しています。

よくある質問
Q. 配列の番号を 1 から始めることはできますか?
A. できます。Dim fruits(1 To 3) As String のように 下限 To 上限 で書けば、1〜3 の3つになります。モジュールの先頭に Option Base 1 と書く方法もありますが、Split の結果など、この設定と関係なく 0 から始まる配列もあります。1 To で明示し、ループは LBound〜UBound で回すほうが混乱しません。
Q. 配列の変数は何型で宣言すればいいですか?
A. 自分で作って中身の型が決まっているなら String や Long、Array 関数の結果やセル範囲を受け取るなら Variant にします。セル範囲の配列には文字と数値が混ざるため、Variant でないと受け取れません。
Q. 配列の中身をまとめて消すには?
A. Erase 配列名 を使います。大きさを決めて作った配列は中身が空に戻り、ReDim で広げた配列は大きさごと消えます。
Q. 配列とコレクション・Dictionary はどう使い分けますか?
A. 件数が決まっている・番号で順に処理するなら配列、名前で探したい・重複をまとめたいなら Dictionary が向いています。実務例のように、読み込みと書き出しは配列、途中の集計は Dictionaryという組み合わせがよく使われます。
まとめ:配列は「読み込み1回・書き戻し1回」で使う
Dim 名前(2)は 0〜2 の3つ。( ) の中は最後の番号- ループは
LBound〜UBoundで回せば、件数が変わっても直さなくてよい - あとから広げるときは
ReDim Preserve。広げられるのは最後の次元だけ - セル範囲から作った配列は 2次元・1 始まり。1セルだけだと配列にならない
- セルを1つずつ触るのをやめて配列でまとめると、2万行で 約1.0秒 → 約0.05秒になった
配列は、最初は番号の数え方で必ず一度つまずきます。でも、エラー9が出たら「箱の番号を数え直す」だけで直ります。まずは「基本1」のコードを貼り付けて実行し、イミディエイトウィンドウに3行出るところから始めてみてください。重かったマクロが一瞬で終わる感覚は、きっとあなたの自信になります。
次に読む


出典(2026年9月26日 確認)
配列の使用 (VBA)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/using-arrays
ReDim ステートメント (VBA)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/redim-statement
UBound 関数 (Visual Basic for Applications)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/ubound-function
Array 関数 (Visual Basic for Applications)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/array-function
Split 関数 (Visual Basic for Applications)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/split-function
Option Base ステートメント (VBA)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/option-base-statement
下付き文字が有効範囲にありません (エラー 9)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/subscript-out-of-range-error-9
Range.Value プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.value
Dictionary オブジェクト|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/dictionary-object

コメント