ExcelでCSV→配列→CSVのような使い方してると「配列データの任意の行を消す」機会がでてきます。
PHPではunset(配列[id])
という便利な命令がありますが、VBAには用意がない。
「VBAじゃなくてExcel上でやってよ〜」とマイクロソフトさんが言ったとか言わないとか(笑) まあ、そりゃそうですよね。そのためのアプリなんだから(笑)
そういうことで自分で作成しました。
仕組みとしては、消す行番号のうしろから1つずつ繰り上げて上書きして、 そのあとに配列のデータ数を再宣言して最後のデータを無視する方法です。
コードです。
Function array_unset(arr() As Variant, n AS Long) As Variant()
Dim i As Long, j As Integer, r As Long, c As Integer
'2次元配列の行列データ数を取ります。
r = UBound(arr,2)’2次元目をRowと見立てる
c = UBound(arr,1)’1次元目をColumnと見立てる
’消したいデータ位置をスタートして、最大数の1個前までループ
For i = n To r - 1
'列方向に項目数ループ
For j = 0 To c
arr(j, i) = arr(j, i+1)
Next j
Next i
ReDim Preserve arr(c, r - 1)’1個減らしてデータを残して再宣言
array_unset = arr ’データを戻します
End Function
VBA上で使うには
2次元配列名 = array_unset(2次元配列名,消したい行番号)
と、こんな感じで使います。
「2次元配列名」は同じでも変えてもOK。
配列を関数に渡して同じ名前に戻すでも、別の配列名でコピーをつくるでもいいです。
配列から関数が受け取ったあとに項目数とデータ数を調べているので、特に気にせずに行削除できるかと思います。
ただ、1つ注意点がありまして、関数に渡す配列はVariant
にしているため、他の形式だとエラーになります。そこを変えたい時はFuntion
の宣言を変えるなどカスタムが必要です。
関数化しないなら、コード内のarr
を任意の配列にすればOKです。コピー配列で消したい時は、処理前に配列名(コピー先)=配列名(コピー元)で作って、コピーの方を処理すればいいですね。
現在VBAでシステムを作成中で煮詰まったので気分転換にさっき作ったユーザー関数を書いてみました。
本当はブラウザでJavaScript使ったほうが処理が早いし、ローカルで仮想サーバー使わせてくれればPHPも使えるのにOKでなかったのでVBAです。いや〜処理が遅い。。。動いているのか心配になるわ(笑)
追記:2023年9月7日
自作システムですぐにこの関数の不具合がでました(笑)
そのとき現場で直したのですが、この記事は直してなかったのに気が付きましたので、直すことにします。(笑)
Function array_unset(arr() As Variant, n AS Long) As Variant()
Dim i As Long, j As Integer, r As Long, c As Integer
'2次元配列の行列データ数を取ります。
r = UBound(arr,2)’2次元目をRowと見立てる
c = UBound(arr,1)’1次元目をColumnと見立てる
If n=0 and r=0 then
'もし配列が1レコードしかなく、それを消す場合
ReDim1(c,0)
Else
'消すデータが最後では無い場合
If n<r then
’消したいデータ位置をスタートして、最大数の1個前までループ
For i = n To r - 1
列方向に項目数ループ
For j = 0 To c
arr(j, i) = arr(j, i+1)
Next j
Next i
End If
’上で1個減らしたのでデータ数を減らして末尾のデータも一緒に消す
'なので、消すデータが最後の場合はこの処理だけで解決
ReDim Preserve arr(c, r - 1)
End If
array_unset = arr ’データを戻します
End Function
この配列レコードが1つしか無いということが少なくて、全く想定もしてなかったので、長いこと不備が見つからず正常に動いちゃってました(笑)
見つかってよかったけど、もっとちゃんとデバックしないとなぁってこのとき思いました。
これ以来、、、、、まあ、、、以前よりはだいぶマシになってますが、まだまだバグだらけのものをリリースしちゃってます(笑)