配列でRANK関数のような処理をする辞書

例えば、以下の配列があるとします。

    Dim seq As Variant
        seq = Array(2, -5, 4, 6.5, 9, 7)

この配列の仕様は、次の通りです。

  1. 数値のみで構成されている。
  2. これらの数値は、不連続な場合がある(例. 1 の次が 3 など)
  3. 並びは順不同である(昇順または降順になっていない)

この中の指定した数値が、配列を昇順にソートした何番目であるか知りたいとき、どうすれば良いでしょうか。周囲に相談したところ、
「RANK関数が使えるのでは?」
という助言をいただいたのですが、Rangeでのみ有効でした。残念。

そこで、RANK関数のような処理をする辞書(連想配列)を作成してみました。
※もっといい方法があると思いますが、探してたどり着けませんでした。

Public Function RankDict(ByVal seq As Variant) As Dictionary

    Dim Dict As Dictionary
    Set Dict = New Dictionary
    
    Dim myMin As Double
        myMin = WorksheetFunction.Min(seq) - 1
    
    Dim i As Long
    Dim j As Long
        j = UBound(seq) - LBound(seq) + 1
        Do
            For i = LBound(seq) To UBound(seq)
                If seq(i) = WorksheetFunction.Max(seq) Then
                    Dict(seq(i)) = j
                    j = j - 1
                    seq(i) = myMin
                    Exit For
                End If
            Next
            If WorksheetFunction.Max(seq) = myMin Then Exit Do
        Loop
        
        Set RankDict = Dict

End Function

配列内で最も大きい値から順に、辞書に登録していきます。

  • キー   配列内の最大値
  • アイテム 何番目の数であるか

辞書に登録したものから、値を「最小値-1」に置き換えていきます。最終的に最大値が「最小値-1」になったところで終了です。

こちらで試してみました。

Sub test()
    Dim seq As Variant
        seq = Array(2, -5, 4, 6.5, 9, 7)        
    Dim Dict As Dictionary
    Set Dict = RankDict(seq)    
    Debug.Print Dict(4)
End Sub

結果は「3」となり、「4」が配列内で3番目に小さい値であることを、同値を引数として得ることが出来ました。

f:id:Infoment:20180912182449p:plain

参考まで。