【Excel VBA】ダックタイピングでマップを実装するコード

スポンサードリンク

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

以上です。


スポンサードリンク

コメントを残す