動的配列って何が「動的」なのか?
前回の「配列宣言」は、こんな形でしたよね。
Dim scores(1 To 5) As Long
VBこれは「5個分」と最初に決めてしまう配列です。
こういうのを「固定配列(固定長配列)」と言います。
でも、実務ではよくこうなります。
- 何件データが来るか、実行してみないと分からない
- 条件に合ったデータだけ集めたいので、件数が読めない
- 途中で「もっと箱が必要になった」「逆に減らしたい」
こういう「サイズが変わるかもしれない」状況で使うのが 動的配列 です。
一言で言うと、
「最初はサイズを決めず、あとから自由に増やしたり減らしたりできる配列」
です。
動的配列の基本:宣言と ReDim の流れ
まずは「サイズなし」で宣言する
固定配列との一番の違いは、宣言のときに「()の中を空にする」ことです。
Dim scores() As Long ' サイズはまだ決めない
VBこの時点では、scores は「箱の数がまだ決まっていない配列」です。
ここが「動的」のスタート地点です。
実際に使うときに ReDim でサイズを決める
必要なサイズが分かったタイミングで、ReDim を使って箱の数を決めます。
ReDim scores(1 To 5)
VBこれで、scores(1)~scores(5) が使えるようになります。
イメージとしては、
「Dim で“動的配列としての箱”を用意」
「ReDim で“何個並べるか”を決める」
という二段構えです。
具体例:5人分の点数を動的配列で持つ
Sub SampleDynamicBasic()
Dim scores() As Long ' 動的配列として宣言
Dim i As Long
ReDim scores(1 To 5) ' ここで5人分と決める
For i = 1 To 5
scores(i) = i * 10
Next i
MsgBox scores(3) ' 3人目 → 30
End Sub
VBこの例だけ見ると「固定配列でもよくない?」と思うかもしれません。
その通りで、「最初から5人と分かっているなら固定配列で十分」です。
動的配列が本領発揮するのは、「何人か分からない」ときです。
実務っぽい例:A列のデータ件数に合わせて配列サイズを決める
データ件数が実行時まで分からないケース
例えば、A列にデータが何行あるか分からないけれど、
「A列の値を全部配列に読み込みたい」とします。
このとき、動的配列はこう使えます。
Sub SampleDynamicFromSheet()
Dim scores() As Variant
Dim lastRow As Long
Dim i As Long
' A列の最終行を求める(よく使う書き方)
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
' データ件数に合わせて配列サイズを決める
ReDim scores(1 To lastRow)
' A列の値を配列に読み込む
For i = 1 To lastRow
scores(i) = Range("A" & i).Value
Next i
MsgBox "配列に " & lastRow & " 件のデータを読み込みました。"
End Sub
VBここでのポイントは、
Dim scores() As Variantで「サイズ未定の配列」として宣言- 実際のデータ件数(lastRow)を調べてから
ReDim scores(1 To lastRow)でピッタリのサイズにする
という流れです。
「データが何件あるか分からないけど、無駄なく箱を用意したい」
というときに、動的配列はとても相性がいいです。
ReDim で「サイズを変える」ときの超重要ポイント
ReDim し直すと、中身は消える
動的配列は、ReDim を何度でも呼び出してサイズを変えられます。
ReDim scores(1 To 3)
scores(1) = 10
scores(2) = 20
scores(3) = 30
ReDim scores(1 To 5) ' ここでサイズを変える
VBここで注意すべきなのは、
普通の ReDim は「前の中身を全部捨てて、新しく作り直す」 ということです。
上の例だと、10,20,30 は消えてしまい、
scores(1)~scores(5) は「中身が初期化された状態」になります。
「サイズを変えたいけど、中身は残したい」
というときに使うのが、次のキーワードです。
ReDim Preserve で「中身を残したままサイズ変更」
Preserve の役割
Preserve を付けると、
「今入っているデータを残したまま、配列のサイズを変更する」
ことができます。
ReDim Preserve scores(1 To 5)
VBこう書くと、
- もともとあった scores(1)~scores(3) の値はそのまま
- scores(4), scores(5) が新しく追加される
という動きになります。
具体例:見つかったデータを順に追加していく
例えば、「A列の中で“完了”と書かれている行だけを配列に集めたい」とします。
何件あるか分からないので、見つかるたびに配列を1つずつ増やしていきます。
Sub SampleDynamicPreserve()
Dim results() As Long ' 行番号を入れる配列
Dim r As Long
Dim count As Long
count = 0
For r = 1 To 100
If Range("A" & r).Value = "完了" Then
count = count + 1
If count = 1 Then
ReDim results(1 To 1)
Else
ReDim Preserve results(1 To count)
End If
results(count) = r ' 見つかった行番号を格納
End If
Next r
If count > 0 Then
MsgBox "完了は " & count & " 件見つかりました。最初の行は " & results(1) & " 行目です。"
Else
MsgBox "完了は見つかりませんでした。"
End If
End Sub
VBやっていることを言葉で整理すると、
- 「完了」を見つけるたびに count を1増やす
- 初回は
ReDim results(1 To 1)で1個分の配列を作る - 2回目以降は
ReDim Preserve results(1 To count)で、
それまでの中身を残したまま、箱を1つ増やす - 新しく増えた位置(results(count))に行番号を入れる
という流れです。
ここでのキモは、
「ReDim だけだと中身が消える。中身を残したいなら ReDim Preserve」
という点です。
ReDim Preserve の制限(最後の次元しか変えられない)
少しだけ踏み込んだ話ですが、ReDim Preserve には重要な制限があります。
「多次元配列のとき、変えられるのは“最後の次元”だけ」
というルールです。
例えば、
Dim table() As Long
ReDim table(1 To 3, 1 To 2)
VBという二次元配列があったとします。
このとき、
ReDim Preserve table(1 To 5, 1 To 2) ' これはエラー(1次元目は変えられない)
ReDim Preserve table(1 To 3, 1 To 4) ' これはOK(2次元目=最後の次元だけ変更)
VBという違いが出ます。
超初心者のうちは、
「ReDim Preserve は“最後の次元だけ”サイズ変更できる」
くらいの理解で十分です。
動的配列を使うときの考え方のコツ
いつ動的配列を選ぶべきか
「固定配列で足りるか?動的配列にすべきか?」の目安はシンプルです。
- 必要な要素数が、コードを書く時点で“確定している”
→ 固定配列でOK - 必要な要素数が、“実行してみないと分からない”
→ 動的配列を検討する価値が高い
特に、Excelのシートからデータを読み込むときは、
「何行あるか分からない」が日常茶飯事なので、
動的配列の出番が多くなります。
「箱の数をあとから決める」という発想に慣れる
固定配列は、
「最初に“何個必要か”を決めてから箱を並べる」
動的配列は、
「とりあえず“箱の種類”だけ決めておいて、
実際に必要になったタイミングで“何個並べるか”を決める」
という違いです。
この発想に慣れると、
- 無駄に大きな配列を用意しなくて済む
- データの増減に強いコードになる
というメリットが出てきます。
まとめ:動的配列は「サイズ未定の配列を、あとから自由に育てる仕組み」
動的配列の本質を一言で言うと、
「サイズをあとから決めたり、変えたりできる配列」
です。
押さえておきたいポイントをギュッとまとめると、
Dim a() As 型で「サイズ未定の配列」として宣言する- 実際に使うときに
ReDim a(1 To n)でサイズを決める - サイズを変え直すとき、普通の
ReDimは中身が消える - 中身を残したいときは
ReDim Preserve a(1 To n)を使う - 「何件あるか分からない」「条件に合うものだけ集めたい」ときに特に強い
