ReDim Preserveとは
VBAで配列を使うとき、「最初は要素数が分からないけれど、処理を進める中で必要な数が分かってくる」という場面はよくあります。このようなときに使うのがReDimステートメントとReDim Preserveステートメントです。
ReDimは配列のサイズを実行時に変更するための命令ですが、そのままだと配列の中身が消えてしまいます。中身を残したままサイズを変更したい場合はPreserveキーワードを追加します。この記事では、ReDimとReDim Preserveの違いや使い方、注意点を実際に動作するサンプルコードとともに解説します。
動的配列の宣言方法
配列には、最初からサイズを固定する「静的配列」と、サイズを後から決める「動的配列」があります。動的配列は、Dim宣言時にサイズを指定せず、カッコを空にして宣言します。
Sub DeclareDynamicArray()
Dim names() As String
ReDim names(2)
names(0) = "田中"
names(1) = "鈴木"
names(2) = "佐藤"
Debug.Print names(0) & ", " & names(1) & ", " & names(2)
End Sub
Dim names() As Stringの時点ではサイズが未確定の状態で、ReDim names(2)を実行した時点で要素数3(インデックス0〜2)の配列として確保されます。
ReDimだけを使うと中身が消える
ReDimは配列のサイズを変更できますが、そのままではそれまで格納していたデータがすべて消えてしまいます。
Sub ReDimWithoutPreserve()
Dim numbers() As Long
ReDim numbers(2)
numbers(0) = 10
numbers(1) = 20
numbers(2) = 30
' サイズを4に変更
ReDim numbers(4)
' 中身は消えてしまい、すべて0になる
Debug.Print numbers(0) & ", " & numbers(1) & ", " & numbers(2)
End Sub
このコードを実行すると、numbers(0)〜numbers(2)はすべて0(数値型の初期値)になってしまいます。サイズ変更のたびにデータが消えるのは不便なため、既存データを残したい場合はPreserveを使います。
ReDim Preserveで中身を残したままサイズ変更する
ReDim Preserveを使うと、既存の要素をそのまま残した状態で配列のサイズだけを変更できます。
Sub ReDimWithPreserve()
Dim numbers() As Long
ReDim numbers(2)
numbers(0) = 10
numbers(1) = 20
numbers(2) = 30
' サイズを4に変更(中身は保持される)
ReDim Preserve numbers(4)
numbers(3) = 40
numbers(4) = 50
Dim i As Long
For i = 0 To UBound(numbers)
Debug.Print "numbers(" & i & ") = " & numbers(i)
Next i
End Sub
このコードでは、既存のnumbers(0)〜numbers(2)の値を保持したまま配列を拡張し、新しく増えたnumbers(3)とnumbers(4)に値を追加しています。
1件ずつデータを追加していく典型パターン
ReDim Preserveは、件数が事前に分からないデータを1件ずつ配列に追加していく処理でよく使われます。UBound関数と組み合わせるのが定番です。
Sub AddItemsOneByOne()
Dim results() As String
Dim count As Long
count = 0
ReDim results(0)
Dim i As Long
For i = 1 To 10
If i Mod 2 = 0 Then
ReDim Preserve results(count)
results(count) = "偶数:" & i
count = count + 1
End If
Next i
' 最後に実際の件数に合わせて調整
If count > 0 Then
ReDim Preserve results(count - 1)
End If
Dim r As Variant
For Each r In results
Debug.Print r
Next r
End Sub
このように、条件に合うデータだけを1件ずつ配列に格納していきたいときに、ReDim Preserveと件数カウンタ用の変数を組み合わせるパターンはよく使われます。
注意点:末尾の次元しかPreserveできない
ReDim Preserveには大きな制約があります。2次元以上の配列では、最後の次元のサイズしか変更できません。
Sub ReDimPreserveTwoDimensional()
Dim data() As Long
ReDim data(2, 3)
' OK:最後の次元(列側)のサイズ変更はできる
ReDim Preserve data(2, 5)
' NG:最初の次元(行側)のサイズを変更しようとするとエラーになる
' ReDim Preserve data(4, 5) ← 実行時エラー
End Sub
行数(1次元目)を変えたい場合にこの制約でつまずくケースが多いです。行方向のサイズも変えたい場合は、CollectionやDictionaryなど他のデータ構造を使うか、配列を作り直して手動でコピーする必要があります。
注意点:ReDim Preserveは処理速度が遅い
ReDim Preserveを実行するたびに、VBAは内部的に新しい配列を確保し、既存のデータをすべてコピーし直しています。そのため、ループの中で毎回ReDim Preserveを呼び出すと、データ件数が多い場合に処理が非常に遅くなります。
件数が多くなることが予想される場合は、あらかじめ大きめのサイズで配列を確保しておき、処理の最後に実際の件数へReDim Preserveで調整する方法がおすすめです。
Sub FasterArrayBuilding()
Dim results() As String
ReDim results(9999) ' 十分大きいサイズで最初に確保
Dim count As Long
count = 0
Dim i As Long
For i = 1 To 10000
If i Mod 3 = 0 Then
results(count) = "3の倍数:" & i
count = count + 1
End If
Next i
' ループの外で1回だけサイズを調整
If count > 0 Then
ReDim Preserve results(count - 1)
End If
Debug.Print "件数: " & (UBound(results) + 1)
End Sub
ループの中でReDim Preserveを呼ぶ回数を最小限にすることで、処理速度を大きく改善できます。
まとめ
ReDimとReDim Preserveの違いと使い方について解説しました。
ReDimは配列サイズを変更できるが、既存データは消えるReDim Preserveは既存データを残したままサイズ変更できる- 多次元配列では最後の次元しかサイズ変更できない
- ループ内で毎回
ReDim Preserveを呼ぶと処理が遅くなるため、可能な限り回数を減らす工夫をする
件数が事前に分からないデータを配列にまとめたい場面は多くあります。ReDim Preserveの特性と制約を理解しておくことで、より安全で効率的なコードが書けるようになります。


コメント