【2026年8月最新】ExcelVBAの動的配列とは?ReDim・Preserveの使い方から静的配列との違いまで完全ガイド
この記事の内容
「Excel VBAで配列を使いたいけど、要素数が実行してみないと分からない…」——集計マクロや在庫リストの処理などを組んでいる方なら、一度はこの壁にぶつかったことがあるはずです。
VBAの配列には、あらかじめ要素数を決めておく静的配列と、実行時に要素数を変えられる動的配列の2種類があります。件数が変動するデータを扱う業務システムでは、動的配列の使い方を理解しているかどうかで、マクロの柔軟性が大きく変わります。
この記事では、配列の基礎から、静的配列と動的配列の違い、ReDim・ReDim Preserveを使った動的配列の書き方、UBound/LBoundを使った応用テクニック、よくあるエラーの対処法までを体系的に整理します。さらに後半では、こうした「地道な集計・データ整形処理」をClaude CodeのようなAIコーディングエージェントにどう任せられるかという実務的な視点も紹介します。
この記事を最後まで読むと、次の6つが明確になります。
01 ARRAY BASICS 配列とは?そもそもの基礎を理解する 複数のデータを1つの変数名でまとめて扱う仕組み
配列とは、複数のデータを1つの変数名でまとめて管理する仕組みです。通常の変数は1つの値しか入れられませんが、配列を使うと「商品名を100件分」「売上金額を1年分」といった複数のデータを、まとめて扱えるようになります。
📚 用語解説
配列(Array):複数の値を1つの変数名の中に、インデックス(添字)と呼ばれる番号で管理する仕組み。VBAでは配列の先頭は基本的に0番目(またはOption Baseの設定次第で1番目)から始まる。
' 通常の変数(1つの値しか入らない)
Dim productName As String
productName = "ノートPC"
' 配列(複数の値をまとめて管理)
Dim productNames(2) As String
productNames(0) = "ノートPC"
productNames(1) = "マウス"
productNames(2) = "キーボード"
この例では、productNames(2)という書き方で「0番目から2番目まで、合計3つの箱を持つ配列」を用意しています。配列の宣言時に指定する数字は「最後のインデックス番号」であり、要素数そのものではない点に注意してください。
Dim arr(2) As Stringは「要素数2」ではなく「インデックス0〜2の合計3要素」を意味します。VBA初学者が最もつまずきやすいポイントの一つです。要素数を正確に数えたい場合は、後述するUBound関数を使うのが安全です。
1-1. なぜ業務マクロで配列が重要なのか
Excelマクロの処理速度は、セルへの読み書き回数に大きく左右されます。セルを1つずつループで読み書きする処理は非常に遅くなりがちですが、配列にまとめてデータを読み込み、配列内で処理をしてから一括でシートに書き戻すことで、処理速度を劇的に改善できるケースが多くあります。
02 STATIC VS DYNAMIC 静的配列と動的配列の違い 「要素数を先に決めるか、後から決めるか」という根本的な違い
VBAの配列は、静的配列(固定長配列)と動的配列(可変長配列)の2種類に大別されます。
| 項目 | 静的配列 | 動的配列 |
|---|---|---|
| 要素数の決定タイミング | 宣言時に固定 | 実行時に自由に変更できる |
| 宣言方法 | Dim arr(9) As String | Dim arr() As String(カッコを空にする) |
| 要素数変更 | 不可(再宣言が必要) | ReDimで何度でも変更可能 |
| メモリの使い方 | あらかじめ確保した分だけ使用 | 必要になった時点で確保・再確保 |
| 向いている場面 | 件数が決まっている固定的な処理(曜日・月など) | 件数が実行時まで分からない処理(検索結果・抽出データなど) |
📚 用語解説
静的配列:宣言した時点で要素数が確定し、実行中に変更できない配列。Dim arr(9) As Stringのように、カッコの中に具体的な数字を書いて宣言する。
📚 用語解説
動的配列:宣言時には要素数を決めず、実行時にReDimステートメントで要素数を指定・変更できる配列。Dim arr() As Stringのように、カッコの中を空にして宣言する。
' 静的配列:要素数があらかじめ確定している
Dim weekdays(6) As String
weekdays(0) = "月": weekdays(1) = "火": weekdays(2) = "水"
' 動的配列:宣言時はカッコを空にする
Dim results() As String
' 実際の要素数は実行時に決まる(後述のReDimで確保)
2-1. どちらを選ぶべきかの判断基準
判断基準はシンプルです。「曜日(7個固定)」「四半期(4個固定)」のように、要素数が絶対に変わらないと分かっている場合は静的配列、「検索結果の件数」「フィルタ後のデータ件数」のように、実行してみないと要素数が分からない場合は動的配列を選びます。
実務のマクロでは「将来的に件数が変わる可能性」を考慮しておいた方が安全なケースが多いです。要素数が本当に固定であると確信が持てる場合を除き、動的配列で組んでおく方が後々の仕様変更に強いコードになります。
2-2. Option Baseが配列の開始番号に与える影響
配列のインデックスは通常0番目から始まりますが、モジュールの先頭にOption Base 1という宣言を書くと、そのモジュール内の配列は1番目から始まる仕様に変わります。
Option Base 1 ' このモジュール内の配列は1始まりになる
Sub Sample()
Dim arr(3) As String ' インデックス1〜3の合計3要素になる
arr(1) = "A"
arr(2) = "B"
arr(3) = "C"
End Sub
Option Base 1は「そのモジュール全体」に影響するため、他の開発者が0始まりを前提にコードを書き足すと、意図しないズレが発生しやすくなります。実務では、Option Baseに頼らず、配列宣言時にDim arr(1 To 3) As Stringのように開始・終了番号を明示的に書く方法が推奨されます。
' Option Baseに頼らず、明示的に開始番号を指定する書き方
Dim arr(1 To 3) As String
arr(1) = "A": arr(2) = "B": arr(3) = "C"
この書き方であれば、Option Baseの設定状況に関係なく、常に「1から始まる配列」であることがコードを見ただけで分かります。チームで開発する場合や、他の人が後から読むコードでは、この明示的な書き方を徹底しておくと事故を防げます。
03 REDIM 動的配列の宣言・ReDimによる初期化 「カッコを空にして宣言」→「ReDimで確保」の2ステップ
動的配列を使うには、「宣言」と「ReDimによる要素数の確保」を分けて書くのが基本の流れです。
' Step 1: 宣言(カッコを空にする)
Dim salesData() As Long
' Step 2: ReDimで要素数を確保
ReDim salesData(9) ' 0〜9の合計10要素を確保
salesData(0) = 15000
salesData(1) = 22000
📚 用語解説
ReDim:動的配列(カッコを空にして宣言した配列)に対して、実行時に要素数を確保・変更するステートメント。「Redimension(再定義する)」の略。何度でも呼び出して要素数を変更できるが、原則として中身のデータは初期化される(消える)点に注意が必要。
3-1. 変数で要素数を指定する
ReDimの真価は、要素数を数値ではなく変数で指定できる点にあります。
Dim recordCount As Long
recordCount = Cells(Rows.Count, 1).End(xlUp).Row - 1 ' データ件数を取得
Dim salesData() As Long
ReDim salesData(recordCount - 1) ' 取得した件数ぶんだけ確保
この書き方により、「シートの最終行を取得して、その件数ぶんだけ配列を確保する」という、実務で最も多用されるパターンを実現できます。データ件数が毎回変わる集計マクロでは、この形が基本になります。
3-2. 多次元の動的配列
動的配列は2次元以上(表形式のデータ)でも使えます。
Dim table() As Variant
ReDim table(recordCount - 1, 2) ' 行数×3列の2次元配列
table(0, 0) = "商品A": table(0, 1) = 100: table(0, 2) = 15000
2次元以上の動的配列にReDim Preserveを使う場合、「最後の次元」しかサイズを変更できません。1次元目(行数)を変えたい場合はPreserveが使えず、データを退避してから配列を再構築する必要があります。詳しくは次章で解説します。
04 ASSIGN VALUES 動的配列に値を代入する方法 ループ処理・セル範囲からの一括代入パターン
動的配列に値を入れる代表的な方法を2パターン紹介します。
4-1. ループで1件ずつ代入する
Dim i As Long
For i = 0 To recordCount - 1
salesData(i) = Cells(i + 2, 2).Value ' 2行目から順に読み込む
Next i
4-2. セル範囲を配列に一括代入する(高速)
件数が多い場合、1件ずつループで代入するより、セル範囲をまるごと配列に代入する方が圧倒的に高速です。
Dim dataRange As Variant
dataRange = Range("A2:C1000").Value ' 範囲全体を一気に配列化
' dataRange(1, 1) が A2セル、dataRange(1, 2) が B2セル...という対応になる
📚 用語解説
Variant型:あらゆるデータ型を格納できるVBAの汎用データ型。セル範囲を配列に一括代入する場合、代入先はVariant型で宣言する必要がある(Rangeの.Valueを配列として受け取る仕様のため)。
ループで1件ずつCells().Valueを読み書きする処理は、セルアクセスのたびに負荷がかかります。範囲をまるごと配列に代入する方法なら、この負荷が1回で済むため、数千行規模のデータでも処理時間を大幅に短縮できます。
05 PRESERVE ReDim Preserveで要素を追加する方法と注意点 既存データを消さずに配列を拡張するテクニック
前述の通り、ReDimは通常配列の中身を初期化(消去)してしまいます。すでに入っているデータを保ったまま要素数だけ増やしたい場合は、ReDim Preserveを使います。
Dim items() As String
ReDim items(2)
items(0) = "A": items(1) = "B": items(2) = "C"
' 要素を1つ追加したい(既存のA・B・Cは残したまま)
ReDim Preserve items(3)
items(3) = "D"
📚 用語解説
ReDim Preserve:ReDimに「Preserve」キーワードを付けることで、配列のサイズを変更しつつ、既存のデータを保持したまま拡張できるようにするステートメント。「保持する」という英単語の意味通り、既存データを残す点がReDim単体との違い。
5-1. ReDim Preserveの注意点:ループ内で多用しない
ReDim Preserveは実行のたびに新しい配列を裏側で確保し直し、既存データをコピーするという処理を行っています。1件ずつ要素を追加するたびにReDim Preserveをループ内で呼び出すと、データ件数が増えるほど処理が急激に遅くなります(件数の2乗に近いペースで遅くなることもあります)。
この問題を避けるには、「あらかじめ十分な余裕を持たせたサイズでReDimし、実際に使った件数だけ後からPreserveで切り詰める」という2段構えの方法が定石です。
Dim results() As String
ReDim results(999) ' 余裕を持って1000件分を先に確保
Dim count As Long
count = 0
Dim i As Long
For i = 1 To 500
If Cells(i, 1).Value > 100 Then
results(count) = Cells(i, 1).Value
count = count + 1
End If
Next i
' ループ終了後、実際に使った件数だけに1回だけPreserveで切り詰める
ReDim Preserve results(count - 1)
ループの中で毎回ReDim Preserveを呼ぶのではなく、「ループの外で最後に1回だけ」呼ぶ設計にすることで、処理速度の劣化を防げます。件数が数百件を超えるマクロでは、この差が体感できるレベルの速度差になります。
先にReDim
余裕を持たせて
1回だけ確保
値を代入
Preserveは
呼ばない
1回だけPreserve
実際の件数に
切り詰める
06 UBOUND LBOUND 【応用】UBound/LBoundで要素数を意識せず操作する 配列の「今の大きさ」をコードに聞く方法
動的配列を扱う実務コードでは、「今、この配列に何個データが入っているか」を都度取得する場面が頻繁に発生します。ここで使うのがUBound関数とLBound関数です。
📚 用語解説
UBound関数:配列の「最大インデックス番号(Upper Bound)」を取得する関数。UBound(arr)と書くと、配列arrの末尾のインデックス番号が返る。「要素数」そのものではなく「番号」である点に注意(要素数を求めたい場合はUBound(arr) - LBound(arr) + 1で計算する)。
📚 用語解説
LBound関数:配列の「最小インデックス番号(Lower Bound)」を取得する関数。多くの場合0が返るが、Option Base 1が設定されている環境や、ReDimで明示的に開始位置を指定した場合は1になることもある。
Dim arr() As String
ReDim arr(5)
Debug.Print UBound(arr) ' → 5 が出力される
Debug.Print LBound(arr) ' → 0 が出力される(通常時)
Debug.Print UBound(arr) - LBound(arr) + 1 ' → 要素数 6 が出力される
6-1. ループの終端をUBoundで動的に指定する
配列の要素数がその都度変わる場合、Forループの終端を固定の数値で書いてしまうと、データが増減するたびにコードを書き直す必要が出てきます。UBoundを使えば、この手間をなくせます。
' NG: 件数を決め打ちしている(データが増えると対応できない)
For i = 0 To 99
Debug.Print results(i)
Next i
' OK: UBoundで「今の配列の大きさ」を毎回聞いている
For i = LBound(results) To UBound(results)
Debug.Print results(i)
Next i
07 ERRORS 動的配列でよくあるエラーと対処法 つまずきやすい3つのエラーメッセージを解説
| エラー内容 | 主な原因 | 対処法 |
|---|---|---|
| 「インデックスが有効範囲にありません」 | ReDimで確保していない要素番号にアクセスしている | 実際に確保した要素数の範囲内かUBoundで確認する |
| 「配列は固定であるか、または一時的にロックされています」 | ReDim Preserveできない次元を変更しようとしている | 2次元配列では最後の次元しかPreserveできない仕様を確認する |
| 意図せずデータが消える | PreserveなしでReDimを呼んでしまっている | 既存データを保持したい場合は必ずReDim Preserveを使う |
| 処理が異常に遅い | ループ内でReDim Preserveを連発している | 余裕を持ったサイズで先にReDimし、最後に1回だけPreserveする |
7-1. デバッグ時に便利な確認方法
動的配列のバグを調査するときは、Debug.Printでイミディエイトウィンドウに現在の状態を出力するのが基本です。
Debug.Print "要素数: " & (UBound(arr) - LBound(arr) + 1)
Debug.Print "LBound: " & LBound(arr) & " / UBound: " & UBound(arr)
動的配列は、宣言しただけでReDimを一度も呼んでいない状態だと「未初期化」の状態になり、UBoundを呼ぶとエラーになります。On Error Resume Nextと組み合わせてUBoundの呼び出しを試す方法が一般的です(IsArray関数は変数が配列型かどうかを判定するのみで、ReDim済みかどうかの判定には使えない点に注意してください)。
7-2. 実践例:条件抽出をまとめて関数化するパターン
条件に合うデータだけを抽出する処理は、業務マクロで最も頻出するパターンの一つです。動的配列・UBound・ReDim Preserveの3点セットを、再利用できる関数の形でまとめておくと、複数のマクロで使い回せて保守性も上がります。
Function FilterOverAmount(dataRange As Range, threshold As Long) As Variant()
Dim result() As Variant
ReDim result(dataRange.Rows.Count - 1) ' 余裕を持って最大件数ぶん確保
Dim i As Long, cnt As Long
cnt = 0
For i = 1 To dataRange.Rows.Count
If dataRange.Cells(i, 1).Value >= threshold Then
result(cnt) = dataRange.Cells(i, 1).Value
cnt = cnt + 1
End If
Next i
If cnt = 0 Then
ReDim result(0 To -1) ' 該当なしの場合は要素数0の空配列を返す(UBoundをLBoundより小さくする)
Else
ReDim Preserve result(cnt - 1) ' 実際の件数に切り詰めて返す
End If
FilterOverAmount = result
End Function
この関数は「範囲」と「しきい値」を渡すだけで、条件に合うデータだけをまとめた配列を返してくれます。呼び出し側のコードは条件判定の詳細を意識せず、「フィルタ後の配列を受け取って使うだけ」というシンプルな形になります。
条件抽出の処理を独立した関数にしておくと、別のマクロやテスト用のシートからも同じロジックを呼び出して検証できます。1つの巨大なSubプロシージャに処理をすべて詰め込むより、機能ごとに小さな関数へ分割しておく方が、後からのデバッグや改修がしやすくなります。
08 COMMON MISTAKES 実務でよくある間違いパターン ここまでの内容を「事故のパターン集」として総整理
| 間違いパターン | 症状 | 対策 |
|---|---|---|
| 要素数を決め打ちしたForループを書く | データ件数が変わると動かなくなる | UBound(arr)でループの終端を動的に取得する |
| ループ内でReDim Preserveを連発する | 件数が増えるほど処理が急激に遅くなる | 余裕を持ってReDimし、最後に1回だけPreserveする |
| ReDimとReDim Preserveを混同する | 既存データが意図せず消えてしまう | データを保持したい場面では必ずPreserveを付ける |
| 多次元配列の1次元目をPreserveで変更しようとする | エラーになる、または意図通りに動かない | 最後の次元しかPreserveできない仕様を理解した上で設計する |
| セルを1件ずつループで読み書きする | 数千行規模で処理が非常に遅くなる | Range().Valueで配列に一括代入してから処理する |
8-1. コードレビューで確認すべきチェックポイント
こうした細かいルールは、データ件数が少ないうちは問題として表面化しません。件数が増えたときに初めて処理速度やエラーとして顕在化するため、レビュー段階で仕組みとして押さえておくことが重要です。
09 AI CODING 【独自】VBAの「地道な処理」をAIに任せる 配列操作・エラー処理のような定型作業にこそAIが効く
ここまで紹介してきた動的配列の宣言・ReDim Preserveの使い分け・UBoundでの動的なループ処理は、「正しく書けば動くが、書き間違えると分かりにくい不具合になる」典型的な領域です。こうした定型的だが間違えやすいコーディング作業こそ、Claude CodeのようなAIコーディングエージェントが力を発揮しやすい領域です。
📚 用語解説
Claude Code:Anthropicが提供するAIコーディングエージェント。「このシートの最終行までのデータを配列に読み込んで、条件に合うものだけ新しい配列にまとめて」といった自然な言葉の指示だけで、ReDim・ReDim Preserve・UBoundを適切に使い分けたVBAコードを生成してくれる。
弊社(株式会社GENAI)では、経理・営業のデータ集計処理にもClaude Codeを活用しています。「この売上データから100万円以上の行だけ抽出して、件数を意識せずに新しいシートにまとめて」といった感覚的な指示でも、動的配列やPreserveの正しい使い方を踏まえたコードを生成してくれるため、VBAの細かい文法を都度調べる手間が大きく減ります。
9-1. 非エンジニアがVBA業務に関わる意味
「VBAなんて自分には書けない」という経営者・事務担当の方も多いはずです。しかし、Excelでの集計・データ整形業務は、多くの会社で今も手作業やコピペで行われている非効率の温床でもあります。「この表からこの条件のデータだけ抜き出して」「件数が変わっても動くようにして」といった要望を、VBAの構文を知らないままClaude Codeに直接伝えて実装させられるのは、非エンジニアにとって大きな価値です。
こう処理したい」
と伝える
感覚的な言葉でOK
VBAコードを生成
動的配列を
適切に設計
動作確認
件数を変えて
テスト
繰り返して完成
試行錯誤の
時間を大幅短縮
もちろん、業務ルールの最終確認や、機密性の高いデータの取り扱いは人間が判断すべき領域です。Claude Codeはあくまで「コーディングの試行錯誤を高速化するアシスタント」という位置づけであり、最終的な業務判断を代替するものではありません。弊社ではVBA・データ処理以外にも営業・広告・経理・秘書業務までClaude Codeを組み込んでおり、月額約30,000円(Max 20xプラン)の投資で、こうした定型コーディング作業まで含めて業務を分担できている肌感があります。
VBA・Excel業務の効率化も、Claude Codeの全社活用も、AI鬼管理が伴走します
「Excelの集計作業を早く終わらせたい」「開発以外の業務にもAIを活かしたい」という経営者・事務担当の方に向けて、Claude Codeの導入設計をサポートしています。
NEXT STEP
この記事の内容を、あなたのビジネスで
実践してみませんか?
AI活用を自社で回せるようになりたい方へ
AI鬼管理
Claude Code・Cowork導入支援から業務設計・社内浸透まで実践ベースで伴走。「自社で回せる組織」を90日で作る経営者向けトレーニング。
よくある質問
Q. 静的配列と動的配列は何が違いますか?
A. 静的配列は宣言時に要素数が固定される配列、動的配列は宣言時にカッコを空にしておき、実行時にReDimで要素数を決める配列です。件数が実行してみないと分からない業務データを扱う場合は、動的配列を使うのが基本です。
Q. ReDimを使うと、配列の中のデータは消えますか?
A. 通常のReDimは配列を初期化するため、既存のデータは消えます。既存データを保持したまま要素数を変更したい場合は、ReDim Preserveを使ってください。
Q. ReDim Preserveをループの中で使ってはいけないのですか?
A. 禁止ではありませんが、ループ内で毎回呼び出すと、件数が増えるほど処理が急激に遅くなります。あらかじめ余裕を持ったサイズでReDimし、ループの外で最後に1回だけPreserveする設計が推奨されます。
Q. UBound関数は何を返す関数ですか?
A. 配列の最大インデックス番号を返します。要素数そのものではない点に注意が必要で、要素数を知りたい場合はUBound(arr) - LBound(arr) + 1で計算します。
Q. 多次元の動的配列でReDim Preserveを使うときの注意点は?
A. 2次元以上の動的配列では、ReDim Preserveで変更できるのは「最後の次元」のみという制約があります。1次元目(行数)を変更したい場合はPreserveが使えないため、別の配列に退避してから再構築するなどの対応が必要です。
Q. VBAでの集計・データ処理をAIツールで効率化できますか?
A. 可能です。Claude CodeのようなAIコーディングエージェントに「この条件でデータを抽出して」と自然な言葉で依頼すると、動的配列やReDim Preserveを適切に使い分けたVBAコードを生成してくれます。VBAの構文を細かく覚えていない方でも活用しやすい方法です。
Claude Codeで業務自動化を90日で叩き込む
経営者向けの伴走型パーソナルトレーニング
Claude Code を業務に落とし込む
専門研修コース一覧
受講者本人の業務を題材に、「使いこなせる」状態になるまで伴走する研修プログラム。1対1特化型・ハンズオン・法人講座の3コースを展開中。業務特化・実装まで踏み込むタイプのClaude Code研修です。
研修コース一覧を見る →AI鬼管理へのお問い合わせ
この記事を読んで気になった方へ。
AI鬼管理の専門スタッフが、御社に最適な
業務自動化プランを無料でご提案します。




