前回の記事では、2次元配列でReDim Preserveを使うと行数を増やせない原因と対処法を解説しました。そのとき、行数が読めないデータをためる方法として3つを紹介すると予告しました。今回はそのうちの1つ、ユーザー定義型(Type)の1次元配列を使う方法を紹介します。
困った場面
2次元配列でデータをためようとすると、ReDim Preserveでは行数を増やせません。あらかじめ最大件数を見積もって確保する方法や、先に件数を数えてから確保する方法もありますが、どちらも一手間かかります(3つの方法の比較はこちら)。
そこで使えるのが、1行分の項目をユーザー定義型(Type)にまとめて、1次元配列でためる方法です。1次元配列ならReDim Preserveで件数をそのまま増やせます。
解決コード
Option Explicit
Private Type TRecord
Id As Long
Name As String
Amount As Long
End Type
Sub AddRecordsWithType()
Dim buf() As TRecord
Dim n As Long
Dim i As Long
Dim srcCount As Long
srcCount = 5 '実際には元データの件数
n = -1
For i = 1 To srcCount
'条件に合うものだけためる想定(ここでは全件ためる例)
n = n + 1
ReDim Preserve buf(0 To n)
buf(n).Id = i
buf(n).Name = "Item" & i
buf(n).Amount = i * 100
Next i
Debug.Print "件数:" & (n + 1)
Debug.Print buf(0).Name & " / " & buf(n).Name
End Sub
解説
1次元だから ReDim Preserve で増やせる
前回の記事で説明したとおり、ReDim Preserveが変更できるのは配列の最後の次元だけです。2次元配列arr(行, 列)では、最後の次元は列なので、増やしたい行数のほうは変えられません。
ユーザー定義型の配列は1次元です。唯一の次元がそのまま「最後の次元」になるので、ReDim Preserveで件数(2次元配列でいう行数にあたる部分)をそのまま増やせます。1行分の複数の値は、配列の次元を増やすのではなく、Type自体のメンバーとして持たせる形です。
そのまま使う場面と、2次元配列に詰め替える場面
ためたデータをそのままループで処理するだけなら、Type配列のまま使えます。たとえば、1件ずつ条件を見て別の処理に渡す、といった使い方です。
一方、シートに一括で書き出したい場合は、最後に2次元配列(またはVariant配列)に詰め替える必要があります。Type配列をそのままVariant変数に代入しようとすると、コンパイルエラーになるためです。
応用はきくが、使う場面を選ぶ理由
Variantに直接入れられない
標準モジュールで定義したTypeの配列は、Variant変数への代入も、Range.Valueへの直接書き出しも、どちらも次のコンパイルエラーになります。


パブリック オブジェクト モジュールで定義されたユーザー定義型に限り、変数に割り当てることができ、実行時バインディングの関数に渡すことができます。
そのため、シートへ一括で書き出したい場合は、2次元配列(またはVariant配列)に詰め替えるか、セル単位で書き込む必要があります。
構造化のままではソートできない
2次元配列やVariant配列なら、シートに貼ってRange.Sortを使う手があります。しかしType配列は、上記の理由でそのままシートに書き出せないため、この手が使えません。詰め替えてからRange.Sortを使うか、自前でソート処理を書く必要があります。
想定外の値を入れたときの挙動
メンバーに型を指定しているため、想定外の値を入れるとエラーになることがあります。ただし、「型が違えば必ずエラー」というわけではありません。実際に試すと、次のようになりました。
- 数値に変換できない文字列(例:
"abc")をLong型メンバーに代入 → 実行時エラー13「型が一致しません」 - 数値として解釈できる文字列(例:
"123")をLong型メンバーに代入 → エラーにならず、123に変換される - 小数を含む数値(例:
100.7)をLong型メンバーに代入 → エラーにならず、101に変換される
つまり、暗黙的に変換できる値はエラーにならず、変換できない値だけエラーになります。「型が違うと必ずエラー」ではなく、「暗黙変換できない値を入れるとエラーになる」というほうが正確です。Variantのメンバーを使えばこのエラー自体は避けられますが、型を指定する意味が薄れるうえ、処理も少し重くなります。
まとめ
- ユーザー定義型(Type)の1次元配列は、
ReDim Preserveで件数を増やせる - そのまま使うか、2次元配列に詰め替えるかは、後続の処理内容で判断する
- Variantへの直接代入やRange.Valueへの直接書き出しはコンパイルエラーになるため、シートに書き出すなら詰め替えが必要
- 構造化のままではソートできない。詰め替えてから
Range.Sortを使うか、自前でソートを書く - 型不一致は「暗黙変換できない値」を入れたときだけエラーになる。数値に変換できる文字列や小数はエラーにならず変換される


コメント