【EXCEL VBA】二次元配列の行の削除はできない。別の配列に「削除しない行」だけコピーして間接的に行の削除をする方法
例えばシート上にあるデータベースを二次元配列に入れ、条件に合った「行」を削除して
別のシートorセルにその配列を貼り付けようとしたとき、EXCEL VBAの二次元配列上では行の削除はできないということが分かった。
EXCEL VBAでは二次元配列の列の削除は出来ても行の削除はできないようになっているらしい。
2つの配列を使う方法
そこで、単一の二次元配列で無理なのであれば、すべてのデータを読み込む配列①と、必要なデータのみをコピーした配列②の2つの二次元配列を用意する方法を思いついたので、実際に動かしてみた。
結論から言って、うまくいった。
まず、このようなデータを用意した。
1行目の見出しも含めて11行×3列のデータになっている。
今回はB列の値が「不要」の行を配列上で削除してみる。
コード全文
今回書いたコードは下記の通り。
Dim arrBf() As Variant Sub array_RowDelete() Dim wS As Worksheet Set wS = ThisWorkbook.Sheets("Sheet1") Dim arrBf() As Variant '全データを入れる二次元配列 ReDim arrBf(11, 3) arrBf = wS.Range("A1:C11").Value Dim arrAf() As Variant '必要な行だけを格納する配列 ReDim arrAf(1 To 11, 1 To 3) Dim i As Long, j As Long Dim cnt As Long cnt = 1 For i = 1 To UBound(arrBf, 1) If arrBf(i, 2) <> "不要" Then 'B列が「不要」でない行だけ処理する For j = 1 To UBound(arrBf, 2) arrAf(cnt, j) = arrBf(i, j) Next j cnt = cnt + 1 End If Next i wS.Range("E1").Resize(cnt, UBound(arrAf, 2)) = arrAf End Sub
解説① 二次元配列の準備
まず、元のデータをすべて取り込むarrBfと、そのarrBfから必要なデータだけを転記するarrAfを用意した(arr_Beforeとarr_Afterの略)。
Dim arrBf() As Variant ReDim arrBf(11, 3) arrBf = wS.Range("A1:C11").Value Dim arrAf() As Variant ReDim arrAf(1 To 11, 1 To 3)
このとき注意したいのがそれぞれの配列のインデックスの範囲。
arrBfはRangeオブジェクトでセルの値をまるまる入れるのでインデックスは自動的に1から始まる。
しかしarrAfはRedimでサイズだけ指定した空の配列なのでインデックスは指定しなければ0から始まる。
このインデックスのずれが後々ややこしくなるため、arrAfの方はわざわざarrAf(1 To 11, 1 To 3)と
インデックスが1から始まるように指定した。
解説② 必要な行を転記する
次にarrBfの2列目の要素を上から順に確認し、「不要」となっていない列をarrAfに移していくコードを書いた。
Dim i As Long, j As Long Dim cnt As Long cnt = 1 For i = 1 To UBound(arrBf, 1) If arrBf(i, 2) <> "不要" Then For j = 1 To UBound(arrBf, 2) arrAf(cnt, j) = arrBf(i, j) Next j cnt = cnt + 1 End If Next i
iはarrBfのすべての行を確認するため、1から11までのイテレータ。
jは「不要」でない行の列を左から数えるため、1から3までのイテレータ。
最後にcntはarrAfにコピーした行をカウントするための変数。
arrBf側の不要行のデータを消すだけではなく行ごと削除するため、上に詰める必要がある。
そのためにcntをarrAf側の行番号として使用することにした。
iを回しながらコピーする行を確認し、arrBf( i , j )の値をarrAf( cnt, j )に移していく作業を繰り返す。
解説③ その他
jを使わなくても
arrAf( cnt , 1 ) = arrBf( i , 1 ) arrAf( cnt , 2 ) = arrBf( i , 2 ) arrAf( cnt , 3 ) = arrBf( i , 3 )
と書いても同じことだけど、元のデータの列が10や20になると記述が大変なので今回はループで書いてみた。
そして最後に必要なデータだけをコピーしたarrAfをE1セルを左上とした範囲に貼り付ける。
wS.Range("E1").Resize(cnt, UBound(arrAf, 2)) = arrAf
この時、もともとarrAfは11行×3列の二次元配列だけど、8行目以降は何のデータも入っておらず不要なので、リサイズする行は cnt を使用する。
これでいちおう、二次元配列の行の削除ができた。
厳密にいうと配列の行は一切削除していないけど、必要行だけ取り出すという当初の目的は達成できたので良しとしよう。
個人的名著