【Excel VBA】Range.Value (2 次元配列) の行・列を操作するクラスのコード – oki2a24 にて RangeValue インスタンスに関数名を引数に渡してマップ処理をできるようにしてみました。けれども、支障があるくらい遅かったですの><。ですので結局マップで回す部分を取り出して、別の関数に渡してやり、結果を RangeValue インスタンスの元の場所に戻してやる、という方法を取りました。
別の方法として、ダックタイピングで関数をもつオブジェクトを RangeValue インスタンスに渡すのはどうかしら?と思いつきました。今回はその記録ですの♪
ポイント
- ダック・タイピング – Wikipedia
- ダックタイピングを試す前は、CallByName を使って擬似的にマップを実現した。
- CallByName は遅かった。
- 引数にオブジェクトを渡し、関数内でオブジェクトにあるはずの関数を呼び出してはどうか? → ダックタイピング
- ダックタイピングでのマップも、思ったほど早くなかった。CallByName よりもわずかに早い程度。比較方法がよくないか?
VBA コード
CallByName とダックタイピングでマップを実装した標準モジュールです。
Option Explicit Public Function MapCallByName( _ ByVal obj As Object, _ ByVal method As String, _ ByVal col As Collection) As Collection Set MapCallByName = New Collection Dim v As Variant For Each v In col Call MapCallByName.Add(CallByName(obj, method, VbMethod, v)) Next v End Function Public Function MapCol( _ ByVal obj As Object, _ ByVal col As Collection) As Collection Set MapCol = New Collection Dim v As Variant For Each v In col Call MapCol.Add(obj.MapColFunc(v)) Next v End Function
マップに渡す関数を定義するクラスです。
Option Explicit Public Function Plus1(ByVal value As Long) As Long Plus1 = value + 1 End Function Public Function MapColFunc(ByVal value As Long) As Long MapColFunc = value + 1 End Function
確認用のテストコードです。
Option Explicit ' CallByName のマップ確認 Public Sub TestMapCallByName() Dim StartTime As Variant, StopTime As Variant StartTime = Time Debug.Print StartTime & " - スタート" Dim befores As Collection: Set befores = New Collection Dim i As Long For i = 1 To 10000000 Call befores.Add(i) Next i Dim ff As FunctionalFunc: Set ff = New FunctionalFunc Dim afters As Collection: Set afters = MapCallByName(ff, "Plus1", befores) StopTime = Time Debug.Print StopTime & " - ゴール" Debug.Print "所要時間 : " & Minute(StopTime - StartTime) & "分" & Second(StopTime - StartTime) & "秒" End Sub ' ダックタイピングのマップ確認 Public Sub TestMapDuckTyping() Dim StartTime As Variant, StopTime As Variant StartTime = Time Debug.Print StartTime & " - スタート" Dim befores As Collection: Set befores = New Collection Dim i As Long For i = 1 To 10000000 Call befores.Add(i) Next i Dim ff As FunctionalFunc: Set ff = New FunctionalFunc Dim afters As Collection: Set afters = MapCol(ff, befores) StopTime = Time Debug.Print StopTime & " - ゴール" Debug.Print "所要時間 : " & Minute(StopTime - StartTime) & "分" & Second(StopTime - StartTime) & "秒" End Sub
結果
20:41:46 - スタート 20:42:07 - ゴール 所要時間 : 0分21秒 20:43:01 - スタート 20:44:21 - ゴール 所要時間 : 0分20秒
おわりに
思ったほど違いがありませんでした。。。コレクションの操作だからかしら?それとも、少し急いでいたので考え違いなどしていたかしら?
最後に、参考ページです。VBA でもダックタイピングができることを知って、試そうという着想がえられましたの!
以上です。