表示されたセル範囲のみ配列に格納するマクロ
2023年08月12日
いつも使っている列集計マクロで、気になることがある。
オートフィルタで絞り込みをしているときに実行すると、
表示中の要素だけ集計してくれると思いきや、
全データを対象に集計になってる。
列要素を集計するマクロ
「お気に入りの集計マクロ」
以前は、対象の列を別シートにコピーしていたので、問題なかったけど、
高速化をするためにセル範囲を配列に格納するように変更したために
全行が対象になっちゃった。
今回は、前に紹介したテーブルの列要素を集計するマクロを改良するにあたって、
配列の要素を格納する処理を表示セルに限定する関数を作った話。
オートフィルタで絞り込みをしているときに実行すると、
表示中の要素だけ集計してくれると思いきや、
全データを対象に集計になってる。
列要素を集計するマクロ
「お気に入りの集計マクロ」
以前は、対象の列を別シートにコピーしていたので、問題なかったけど、
高速化をするためにセル範囲を配列に格納するように変更したために
全行が対象になっちゃった。
今回は、前に紹介したテーブルの列要素を集計するマクロを改良するにあたって、
配列の要素を格納する処理を表示セルに限定する関数を作った話。
セル範囲から配列に格納する処理は、以下のとおり。なんと1行。
該当箇所
Dim MyArr: MyArr = range(Cells(タイトル行 + 1, 対象列), Cells(最終行, 対象列)).Value
バリアント型で宣言しておいて、セル範囲の値を格納するだけ。
要素は1から始まって、MyArr(行,列)の形になる。
格納するときは、上の逆操作するだけ。
tarRange = MyArr
ざっと検索したところ、表示中の行のみを配列に格納する機能は用意されていないらしく、
コピペでやるか、SpecialCells(xlCellTypeVisible)でやるか、行ループでやるかの3択。
キーワード
VBA 配列 格納 表示中のみ
コピペを使用する処理は、バックグラウンドで動かしたときにクリップボードの内容が変わっちゃうので使いたくない。
SpecialCellsは、ちょっと試してみたけどうまくいかず。。。
行ループは泥臭くてめんどくさいなぁと思い、手付かずになっていたけど、
やっと重い腰を上げた次第。
配列に格納するだけであれば、処理速度はそこまで遅くないと思うので、
行ループを作って、以下の判定処理をすることにした。
If Rows(Gyo).Hidden = False Then
完成した関数の処理の流れは以下の通り。
対象範囲の値を配列に格納。
非表示行を除外した出力用配列に使用するポインタを辞書型配列で用意。
行ループで、各行が表示されているか判定して
出力用配列の各行が、元の配列の何行目を参照するかを辞書型配列ポインタに格納。
行ループが終わったら、
作成したポインタをもとに出力用配列を作成。
列データ用に作ったけど、複数列の場合も考慮。
実際に集計マクロに組み込んでみたところ、
合計の計算や割合の計算がタイトル行と最終行を使ってて撃沈。
この話はまた今度。
参考にしたサイト
エクセルの真髄
https://excel-ubara.com/excelvba1/EXCELVBA414.html
以下、ソース。
Sub sheet2Arr_test()
Dim testA: testA = sheet2Arr(Selection)
Stop
End Sub
Function sheet2Arr(tRange As Range)
Dim stGyo As Long: stGyo = tRange(1).row
Dim edGyo As Long: edGyo = tRange(tRange.Count).row
Dim posDic: Set posDic = CreateObject("Scripting.Dictionary")
Dim Gyo As Long, i As Long, j As Long, k As Long
For Gyo = stGyo To edGyo
i = i + 1
If Rows(Gyo).Hidden = False Then
k = k + 1
posDic.Add k, i 'ポインタ viArr(k)=myArr(i)
End If
Next Gyo
Dim myArr: myArr = tRange.Value
Dim jMax As Long: jMax = UBound(myArr, 2)
Dim kMax As Long: kMax = k
Dim viArr(): ReDim viArr(1 To kMax, 1 To jMax)
For k = 1 To kMax
For j = 1 To jMax
viArr(k, j) = myArr(posDic(k), j)
Next j
Next k
sheet2Arr = viArr
End Function
PR
Comment