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

Excel VBA の ReDim — ReDim と ReDim Preserve で配列をリサイズする

|

Excel VBA の ReDim — ReDim と ReDim Preserve で配列をリサイズする

TL;DR — VBA の配列は、角かっこを空にしておかないかぎり、Dim した瞬間にサイズが固定されます。 Dim a() はまだサイズのない 動的 配列を宣言し、ReDim a(1 To 10) がそこにサイズを与えます。素の ReDim は保持していた値をすべて捨ててしまうので、データを失わずに配列を伸ばすには ReDim Preserve を使います。落とし穴はこうです。二次元配列では、ReDim Preserve最後の 次元しかリサイズできませ ん。固定サイズの配列(Dim a(1 To 10))は、そもそも一度も ReDim できません。

Sub GrowAnArray()
    Dim a() As Long                 ' 動的 - まだサイズがない
    ReDim a(1 To 3)                 ' これで Long を 3 個持つ
    a(1) = 10: a(2) = 20: a(3) = 30

    ReDim Preserve a(1 To 5)        ' 5 個に伸ばす、10, 20, 30 は残す
    a(4) = 40: a(5) = 50            ' ここで素の ReDim なら 10-30 が消えていた
End Sub

ReDim動的 配列の物語そのものです。配列を Dim a() で開いたまま宣言し、 ReDim でサイズを与え、UBound でどれだけの大きさになったかを尋ね、そして — グリッドなら — 伸ばせるのは最後の次元だけだと覚えておきます(VBA 2D Arrays を参 照)。ReDim を間違えるとデータは静かに消えてしまうので、サイズが いつ 固定され、いつそうでないのかを 理解しておく価値があります。

この記事で学べること

  • すべての配列を左右する唯一の判断 — Dim で固定サイズにするか、Dim a() で開いておくか
  • ReDim が動的配列にサイズを与えるしくみ、そして 素の ReDim が保持していたものをすべて消す理由
  • ReDim Preserve — 配列を伸ばしつつデータを保つ方法
  • 第一の罠 — ReDim Preserve は二次元配列の 最後の 次元しかリサイズできない
  • 固定サイズの配列を ReDim できない理由、そして Erase が実際に何をするのか
  • ループの中で配列を一行ずつ伸ばすとなぜ遅いのか、そして代わりにどうすべきか

考え方の軸:Dim で固定するか、空の角かっこで開くか

VBA の配列は二種類のどちらかであり、どちらにするかは宣言時に選びます。

Dim fixed(1 To 10) As Long   ' 固定 - 10 個の枠、ずっと変わらない; サイズは型の一部
Dim flex() As Long           ' 動的 - まだサイズがない; あとで ReDim する

固定サイズ の配列は一度だけサイズが決まり、二度と変わりません — サイズが宣言の中に宿っているので、VBA はあとから ReDim させてくれません(コンパイルエラー Array already dimensioned が出ます)。動的 配 列は空の角かっこで宣言します。型はあってもサイズはなく、ReDim こそがそれにサイズを与える手段です。この 一つの選択 — Dim の時点で角かっこを埋めるか空にするか — が、このページの残りすべてを決めます。いくつ項 目を持つことになるかまだ分からないなら、開いたまま宣言しましょう。

ReDim は動的配列にサイズを与える

ReDim は動的配列に新しい記憶領域を割り当てます。同じ配列を好きなだけ ReDim でき、それぞれの ReDim は上限・下限すら変えられます。

Dim a() As String
ReDim a(1 To 3)      ' 3 要素、添字は 1..3
ReDim a(0 To 99)     ' これで 100 要素、添字は 0..99

頭に入れておくべきことが一つあり、それが「データが消えた」というバグのほとんどの原因です。素の ReDim配列全体を初期化し直します。すべての要素が既定値へ戻り — 数値なら 0、文字列なら ""、オブジェク トなら Nothing — まるで今作ったばかりのようになります。

Dim a() As Long
ReDim a(1 To 3)
a(1) = 10: a(2) = 20: a(3) = 30
ReDim a(1 To 5)      ' a(1..3) はまた 0 に戻る - 値は消えた

データを残すつもりだったなら、まさにそのために Preserve があります。

ReDim Preserve:データを失わずに伸ばす

ReDim Preserve は、リサイズした配列を返す前に、既存の値をその中へコピーします。

Dim a() As Long
ReDim a(1 To 3)
a(1) = 10: a(2) = 20: a(3) = 30
ReDim Preserve a(1 To 5)   ' a(1..3) はまだ 10, 20, 30 を保持; a(4), a(5) は 0

すでに埋めた配列を拡張するときはいつでも Preserve を使いましょう。伸ばすときも 縮める ときも動きます — 縮める場合は、新しい上限を超えた要素が単に捨てられるだけです。守らなければならない唯一の規則は次元につ いてのもので、そこでほとんど誰もがつまずきます。

第一の罠:Preserve は最後の次元しかリサイズできない

一次元配列では、ReDim Preserve は上限・下限を自由に変えられます。二次元 配列では、ReDim Preserve最後の 次元しか変えられません。最初の次元を変えようとすると、VBA は実行時エラー 9、 Subscript out of range を発生させます。

Dim g() As Long
ReDim g(1 To 3, 1 To 2)          ' 3 行、2 列
ReDim Preserve g(1 To 5, 1 To 2) ' エラー 9 - 最初の次元はリサイズできない
ReDim Preserve g(1 To 3, 1 To 4) ' OK - 最後の(列の)次元は伸ばせる

これは、もっと巧妙な ReDim で回避できるバグではありません。VBA がメモリ上で配列をどう格納するか、その ものだからです。直感にも反します。シートは × 列なので、たいてい欲しい「伸ばす」— 行を足すこと — は 最初の次元、つまり触れてはいけない次元にあたるからです。抜け道は二つ。グリッドを × 行として宣言し、 伸ばす次元を最後に持ってくるか、あるいはもっと一般的には、ループの前に配列を最終的な行数へ一度だけサイズ 指定し、Preserve はいっさい使わないことです。既存の二次元配列にどうしても行を足さなければならないなら、 作り直します(あるいは転置し、最後の次元をリサイズし、また転置し戻します)。詳しくは VBA 2D Arrays にあります。

固定サイズの配列は ReDim できない

ReDim は空の角かっこで宣言した配列専用です。Dim の時点で配列にサイズを与えたなら、そのサイズは宣言に 焼き込まれ、ReDim はコンパイルエラーになります。

Dim a(1 To 10) As Long
ReDim a(1 To 20)      ' コンパイルエラー - "Array already dimensioned"

配列をリサイズしたくなったとしたら、それはそもそも動的(Dim a())として宣言すべきだった、という合図で す。個数が分かった直後に一度だけ ReDim する動的配列は、両方のいいとこ取りを与えてくれます。実行時に選 んだ、すっきりした固定の作業用サイズです。

Erase:初期化するか、解放するか

Erase は、配列の種類によって二つの異なることをします。固定サイズ の配列では、すべての要素を既定値へ 戻しますが、配列のサイズはそのまま保ちます。動的 配列では、さらに踏み込みます — メモリを解放し、まる で Dim a() としか書いていなかったかのように、配列をサイズのない状態へ戻します。

Dim fixed(1 To 3) As Long
Erase fixed            ' 3 要素すべてがまた 0 に; サイズは 3 のまま

Dim flex() As Long
ReDim flex(1 To 3)
Erase flex             ' メモリが解放される; flex はまたサイズなし - 再利用の前に ReDim

動的配列を Erase したあとは、もう一度 ReDim するまで、それに対して UBound を呼 ぶと実行時エラー 9 が出ます — 配列には本当に報告すべき上限・下限がないのです。

一度でサイズを決め、一つずつ伸ばさない

ReDim Preserve は毎回、新しいブロックを割り当てて古い中身をそこへコピーするので、ループの一周ごとに配 列を一つずつ伸ばすと、O(n) の仕事が O(n²) になってしまいます — 50 項目なら問題ありませんが、50,000 項目 ではつらくなります。定石の直し方は、すでに手元にある個数(最終行、コレクションのサイズ)を使って、最初に 一度だけ配列をサイズ指定し、必要なら最後に切り詰めるだけにすることです。

Dim a() As Long, n As Long, i As Long
n = Cells(Rows.Count, 1).End(xlUp).Row   ' データの行数
ReDim a(1 To n)                          ' 割り当ては一度だけ
For i = 1 To n
    a(i) = Cells(i, 1).Value
Next i

個数を事前に本当に知りようがないときの定番は、大きめのかたまりで ReDim し(たとえば足りなくなったらサ イズを倍にする)、最後に一度だけ正確な個数まで ReDim Preserve で縮めることです — 毎回一つずつ伸ばすよ りコピーの回数がはるかに少なくて済みます。

ExcelMaster の活用

ReDim をめぐる話はすべて、一つの判断に尽きます — この配列は固定サイズか、それとも伸びるのか? — そして 典型的な失敗は二つ、データを静かに消してしまう素の ReDim と、間違った次元で実行時エラー 9 にぶつかる ReDim Preserve です。

ExcelMaster には、やりたいことをそのま ま伝えられます — 「A 列を配列に読み込んで、空白でない値だけ残して、C 列に書き出して」 — すると、配列を動 的に宣言し、実際の行数から一度だけサイズを決め、次元が許す場所でだけ ReDim Preserve を使い、セルを一つ ずつではなく範囲を一度で読み取ります。ブックとコードはあなたの手元に残ります。

よくある質問

VBA の ReDim は何をするのですか?

ReDim は動的配列 — Dim a() As Long のように空の角かっこで宣言した配列 — のサイズを設定、または変更し ます。ReDim a(1 To 10) は配列に 10 要素を与えます。同じ配列を繰り返し ReDim でき、それぞれの ReDim で上限・下限を変えられます。素の ReDim はすべての要素を既定値へ初期化し直しもするので、既存のデータを 保つ必要があるときは ReDim Preserve を使いましょう。

ReDim と ReDim Preserve の違いは何ですか?

素の ReDim は新しいサイズを割り当て、すべての要素を既定値へ戻し、配列が保持していたものを捨てます。 ReDim Preserve は先に既存の値をリサイズ後の配列へコピーするので、データは生き残ります。最初のサイズ指 定には素の ReDim を、すでに埋めた配列を拡張するときはいつでも ReDim Preserve を使いましょう。

二次元配列で ReDim Preserve が実行時エラー 9 を出すのはなぜですか?

ReDim Preserve は多次元配列の 最後の 次元しかリサイズできないからです。最初の次元を変えると、実行時 エラー 9、Subscript out of range が発生します。グリッドに「行」を足すには、列 × 行として宣言して伸びる 次元を最後にするか、ループの前に最終的な行数へサイズ指定するか、配列を作り直しましょう。

固定サイズの配列を ReDim できますか?

いいえ。Dim a(1 To 10) のようにサイズ付きで配列を宣言したなら、そのサイズは型の一部であり、ReDim は コンパイルエラー Array already dimensioned になります。ReDim でサイズを与えたりリサイズしたりできるの は、空の角かっこ(Dim a())で宣言した配列だけです。

VBA の配列に要素を追加するには?

個数を自分で管理し、ReDim Preserve で場所を空けます。ReDim Preserve a(1 To n + 1): a(n + 1) = value: n = n + 1。これで動きますが、要素ごとにリサイズするのは遅いです。ReDim Preserve は毎回、配列全体をコピ ーするからです。大きなループでは、分かっている個数から一度だけサイズを決めるか、かたまりで伸ばして最後に 一度切り詰めましょう。個数が本当に不明なときは、Collection のほうが簡単なことが多いです。

検証環境

動作確認: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-24.

関連ガイド: VBA UBound · VBA 2D Arrays · VBA Array · VBA Dim · VBA For Loop