🚀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