線形4分木ですが、どの様な形で返そうか? 空間の再分割が
つらいのでやめようか 等があり、ナカナカ進みません。
もう一つ悩んでいるのが、VBAのコレクション。今更ですがコレクションの
Itemがプロパティではなく、メソッドになっていることに嫌気がさして
きたので他のものを使うことにします。
手頃そうなものを探したところ、こちらを見付けました。
AarrayListをvbaで使いやすいようにラップしてみた : 趣味のプログラムあれこれ
DotNetFrameworkのArrayListのラッパークラスです。
折角なのでテストしてみました。
(クラスの名称が長かった為、cListとしています)
'vba test_ArrayList using-'KCL0.09' '.NETFramework_ArrayList_Rapper_Class Test 'http://blog.livedoor.jp/midorityo/archives/50749809.html Sub CATMain() Dim Lst As cList: Set Lst = New cList With Lst .Add 1 .Add 10 .Add 21 .Add 21 .Add -5 .Add 3 End With Call DumpList(Lst) 'インデクサ NG 'Debug.Print lst(1) '代入 Lst.Item(0) = 100: Call DumpList(Lst) 'Sort Call Lst.Sort: Call DumpList(Lst) 'Reverse Call Lst.Reverse: Call DumpList(Lst) 'BinarySearch Call DumpValue(Lst.BinarySearch(21), "Idx:") Call DumpValue(Lst.BinarySearch(2), "Idx:") 'IndexOf Call DumpValue(Lst.IndexOf(21), "IndexOf:") Call DumpValue(Lst.IndexOf(2), "IndexOf:") 'LastIndexOf Call DumpValue(Lst.LastIndexOf(21), "LastIndexOf:") Call DumpValue(Lst.LastIndexOf(2), "LastIndexOf:") 'Contains Call DumpValue(Lst.Contains(21), "Contains:") Call DumpValue(Lst.Contains(2), "Contains:") 'Insert Call Lst.Insert(1, 99): Call DumpList(Lst) 'ToString Call DumpValue(Lst.ToString, "ToString") 'TrinToSize Call DumpValue(Lst.capacity, "TrinToSize_Before:") Call Lst.TrinToSize Call DumpValue(Lst.capacity, "TrinToSize_After:") 'Clear Call Lst.Clear: Call DumpList(Lst) 'capacity Set Lst = New cList Call KCL.SW_Start Call DumpValue(Lst.capacity, "non_capacity:") Set Lst = InitRngList(Lst, 32766) Call DumpValue(KCL.SW_GetTime, , "s") Set Lst = New cList Call KCL.SW_Start Lst.capacity = 32767 Call DumpValue(Lst.capacity, "use_capacity:") Set Lst = InitRngList(Lst, 32766) Call DumpValue(KCL.SW_GetTime, , "s") End Sub Private Function InitRngList(ByVal Lst As cList, ByVal count&) As cList Dim i& For i = 0 To count Lst.Add i Next Set InitRngList = Lst End Function Private Sub DumpList(ByVal Lst As cList) Debug.Print "---" For i = 0 To Lst.count - 1 Debug.Print Lst.Item(i) Next End Sub Private Sub DumpValue(ByVal v, _ Optional ByVal msg_s$ = vbNullString, _ Optional ByVal msg_e$ = vbNullString) Debug.Print "---" Debug.Print msg_s & v & msg_e End Sub
内容的には意味は無いのです。インデクサが無いのとForEach出来ない
部分がちょっと物足りないのですが、それ以上に不安を感じるのが
capacityの値が32767以上ではオーバーフローになってしまい、少なすぎる
気がしてます。(要素をAdd出来る最大数です)
"ForEach出来ない" 部分は、こちらを参考に修正してみましたがNG
でした。VBAのコレクションのみのお話なのでしょう。
(ArrayListクラスには、NewEnumがありません)
単純に考え、ArrayListを返すための "ToList" メソッドをクラスモジュールに
追記しました。
Function ToList() As Variant Set ToList = arraylist End Function
これであれば、こんな感じでForEach出来ます。
Private Sub DumpList(ByVal Lst As cList) Debug.Print "---" For Each v In Lst.ToList Debug.Print v Next End Sub
そんな事を試しているうちに、こちらの記述を見つけました。
VBAのコレクションへの添え字によるアクセスを早くする - Qiita
ん~VBAコレクションのキー付き(辞書型っぽい使い方)の呼び出しが
想像以上に速い。知らなかったです。
DotNetFrameworkのArrayListが遅いのは、C#をやっていた頃に
知りました。(現在はジェネリックコレクションがある為、基本ArrayListは
利用されていないはず)
で、気を取り直し試してみました。
Sub CATMain2() Dim Lst As cList: Set Lst = New cList Set Lst = New cList Call KCL.SW_Start Lst.capacity = 32767 Set Lst = InitRngList(Lst, 32766) '--loop-- 'For Call KCL.SW_Start For i = 0 To Lst.count - 1: dmy = Lst(i): Next Call DumpValue(KCL.SW_GetTime, "For: ", "s") 'ToArray_For Call KCL.SW_Start Ary = Lst.ToArray For i = 0 To UBound(Ary) - 1: dmy = Ary(i): Next Call DumpValue(KCL.SW_GetTime, "ToArray_For: ", "s") 'ForEach Call KCL.SW_Start For Each v In Lst.ToList: dmy = v: Next Call DumpValue(KCL.SW_GetTime, "ForEach: ", "s") 'ToList_ForEach Call KCL.SW_Start Set L = Lst.ToList For Each v In L: dmy = v: Next Call DumpValue(KCL.SW_GetTime, "ToList_ForEach: ", "s") End Sub
cListを
・素の状態でFor
・ToArrayで代入してFor
・追記したToListをそのままForEach
・追記したToListを代入してからForEach
結果はこちら
--- For: 0.516s --- ToArray_For: 0.003s --- ForEach: 0.018s --- ToList_ForEach: 0.018s
以前、"ForよりForEachの方が速い" と思っていたのですが、
VBAのコレクションをForをするのが遅いのであって、For自体は速いんですね。
capacityが小さいから、配列とコレクションと併用しようかな。
(かなりわかりにくくなりそう)