VBAには配列のshiftメソッドは無い
主にWeb系で扱うプログラミング言語には配列の操作を行うメソッドがあります。ここでは配列の先頭データを切り取る処理をVBA用にした関数を紹介します。
先頭を切り取る処理はプログラミング言語によって関数名は異なりますが、JavaScriptやPHPやRubyなど一般的には「shift」という名前が多いため、以下で紹介する関数はそれに合わせて「ArrayShift」という関数名にしています。
配列の先頭や終端にデータの追加や削除を行うには
VBAの配列は単にデータを複数保持しているだけですが、現在主流のプログラミング言語では配列はクラスとして管理されており、配列を操作するための関数が複数用意されていることが一般的です。
プログラミング言語によって関数名は異なりますが、配列を操作する関数として一般的には以下のようなものがあります。
関数名 | 用途 | 関数戻り値 |
---|---|---|
shift | 配列の先頭データを切り取る | 切り取った先頭データ |
unshift | 配列の先頭にデータを追加する | 追加後の配列要素数 |
pop | 配列の終端データを切り取る | 切り取った終端データ |
push | 配列の終端にデータを追加する | 追加後の配列要素数 |
これらの関数をVBAでも使えるように以下に説明します。なお、それぞれの実装方法が異なるためページを分けて説明しています。
- VBAの配列の先頭データを切り取る(shift) 当ページ
- VBAの配列の先頭にデータを追加する(unshift)
- VBAの配列の終端データを切り取る(pop)
- VBAの配列の終端にデータを切り取る(push)
配列の先頭データを切り取るコード(shift)
以下のコードは配列の先頭(配列のインデックスが0)のデータを切り取る関数です。JavaScriptやPHPなどでのshiftメソッドになります。
使い方ですが、関数の引数には配列を渡し、関数の戻り値は切り取ったデータを返します。関数実行後は配列の要素数は先頭データが無くなるため1減ります。
配列は1次元配列を対象としており、配列のデータ型はなんでもOKです。なんでもOKにするために、オブジェクト型かどうかの判定をIsObject関数で行い、オブジェクト型であれば値の代入方法でSetを使い、そうでなければ=で代入するようにしています。
IsObject関数の詳細については「VBAのオブジェクト変数かどうかを判定する(IsObject)」をご参照ください。
引数が配列でない場合は処理しません。また、配列の要素がない場合は先頭データを戻り値用に切り取り、配列をクリアしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
'// 先頭を切り取る '// 引数:配列 '// 戻り値:切り取った先頭データ Function ArrayShift(ar As Variant) As Variant '// 引数が配列でない場合 If IsArray(ar) = False Then '// 処理せず抜ける Exit Function End If '// 配列要素数を取得 Dim iSize As Long '// 配列サイズ iSize = UBound(ar) '// 配列の先頭を戻り値として取得 '// オブジェクト型変数の場合 If IsObject(ar(0)) = True Then Set ArrayShift = ar(0) '// プリミティブ型変数(IntegerやStringなど)の場合 Else ArrayShift = ar(0) End If '// 配列にデータが複数ない場合 If iSize = 0 Then '// 配列をクリア(先頭データを削除)して処理を抜ける ReDim ar(0) Exit Function End If Dim i As Long '// ループカウンタ '// 配列要素数ループ(2番目の要素から処理する) For i = 1 To iSize '// オブジェクト型変数の場合 If IsObject(ar(i)) = True Then '// 1つ前の要素に現在ループ値を設定 Set ar(i - 1) = ar(i) '// プリミティブ型変数(IntegerやStringなど)の場合 Else '// 1つ前の要素に現在ループ値を設定 ar(i - 1) = ar(i) End If Next '// 終端の要素を削除 ReDim Preserve ar(UBound(ar) - 1) End Function |
使い方
上のArrayShift関数をString型の配列とRange型の配列のそれぞれを使った場合の利用例です。
引数に配列を渡すだけですが、戻り値の受け取り方が配列のデータ型がオブジェクト型かそうでないかの2通りあります。
以下のコードのString型はプロパティやメソッドを持たないプリミティブ型の1つで、ArrayShift関数の結果を=の代入で取得できます。Range型はクラスのためオブジェクト型の1つになり、ArrayShift関数の結果をSetステートメントを使って取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Sub ArrayShiftTest() Dim ar() As String Dim s '// String型配列 ReDim ar(3) ar(0) = "abc" ar(1) = "bbb" ar(2) = "ccc" ar(3) = "ddd" '// 先頭を切り取り s = ArrayShift(ar) Debug.Print s '// 切り取った abc を出力 Debug.Print UBound(ar) '// 要素が1つの配列 ReDim ar(0) ar(0) = "!" '// 先頭を切り取り s = ArrayShift(ar) Debug.Print s '// 切り取った ! を出力 Debug.Print UBound(ar) '// Range型配列 Dim r() As Range ReDim r(2) Dim ss As Range Set r(0) = Range("A1") Set r(1) = Range("B2") Set r(2) = Range("C3:D4") '// 先頭を切り取り Set ss = ArrayShift(r) Debug.Print ss.Address(False, False) '// 切り取ったセルのアドレスA1を出力 Debug.Print UBound(r) End Sub |
実行結果
abc
2
!
0
A1
1