【ExcelVBA・マクロ】ReDim Preserveの使い方|動的配列のサイズを実行時に変更する方法【コピペOK】

ExcelVBA

ReDim Preserveとは

VBAで配列を使うとき、「最初は要素数が分からないけれど、処理を進める中で必要な数が分かってくる」という場面はよくあります。このようなときに使うのがReDimステートメントとReDim Preserveステートメントです。

ReDimは配列のサイズを実行時に変更するための命令ですが、そのままだと配列の中身が消えてしまいます。中身を残したままサイズを変更したい場合はPreserveキーワードを追加します。この記事では、ReDimReDim 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次元目)を変えたい場合にこの制約でつまずくケースが多いです。行方向のサイズも変えたい場合は、CollectionDictionaryなど他のデータ構造を使うか、配列を作り直して手動でコピーする必要があります。

注意点: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を呼ぶ回数を最小限にすることで、処理速度を大きく改善できます。

まとめ

ReDimReDim Preserveの違いと使い方について解説しました。

  • ReDimは配列サイズを変更できるが、既存データは消える
  • ReDim Preserveは既存データを残したままサイズ変更できる
  • 多次元配列では最後の次元しかサイズ変更できない
  • ループ内で毎回ReDim Preserveを呼ぶと処理が遅くなるため、可能な限り回数を減らす工夫をする

件数が事前に分からないデータを配列にまとめたい場面は多くあります。ReDim Preserveの特性と制約を理解しておくことで、より安全で効率的なコードが書けるようになります。

スポンサーリンク
スポンサーリンク
ExcelVBA
シェアする
いがぴをフォローする

コメント

タイトルとURLをコピーしました