【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 でもダックタイピングができることを知って、試そうという着想がえられましたの!
以上です。
