Windows 10 Pro_x64 + Excel2013_x86 VBA で Dictionary を辞書順にソートする

Windows 10 Pro_x64 + Excel2013_x86 VBA で Dictionary を辞書順にソートする

 

基本的に、AarrayList を参照後、keyを突っ込んで sort することが多いんだけど

参照に制限が付いた気がするので、Dictionaryで代用できるようにする

※.Net Library 3.5 まで参照可ってソースが見つからない

※ソートはMSのサイトにあった気がするんだが、消えているんだよなぁ・・・

 

参考にしたのは以下のサイト

VBAでDictionary(連想配列)を辞書順にソートする

・Option Explicit が通るコードに修正

・可変長配列の切り方を修正

・その他、自分なりのコメントを追加

・UserFormを1個追加する

・CommandButtonを1個追加する

・2次元の文字型の配列で動作することも確認する

※For Each key In dic -> Doc.Keys で取る必要はなかったのか・・・

Option Explicit

Private Sub CommandButton1_Click()
'
    Dim key     As Variant
    Dim dic     As Object
    Dim output  As String
'
    Set dic = CreateObject("Scripting.Dictionary")
'
    dic("g") = "gggg"
    dic("9") = "999"
    dic("を") = "をををを"
    dic("4") = "444"
    dic("あ") = "ああああ"
    dic("(") = "(((("
    dic("a") = "aaaa"
'
    output = "##before" & vbNewLine
    For Each key In dic
        output = output & key & ":" & dic(key) & vbNewLine
    Next key
'
    Call DicSort(dic)
'
    output = output + "##after" & vbNewLine
    For Each key In dic
        output = output & key & ":" & dic(key) & vbNewLine
    Next key
'
    MsgBox output
    '
    '   文字型の2次元配列のソート
    '
    Dim typArry(3, 1)   As String
    Dim i               As Integer
    '
    '   配列の添え字の最小値は0
    '   typArry(0, 0)~typArry(3, 1)
    '
    typArry(0, 0) = "01"
    typArry(0, 1) = "北海道"
    typArry(1, 0) = "02"
    typArry(1, 1) = "青森県"
    typArry(2, 0) = "03"
    typArry(2, 1) = "岩手県"
    typArry(3, 0) = "01"
    typArry(3, 1) = "北海道"
'
    Call QuickSort(typArry, LBound(typArry), UBound(typArry))
'
    For i = LBound(typArry) To UBound(typArry)
        Debug.Print typArry(i, 0), typArry(i, 1)
    Next
'
End Sub

'=================================================================
' 名 称 : DicSort
' 機 能 : 引数のDictionaryをソートする破壊的プロシージャ
' パラメータ : Dictionary
'=================================================================
Sub DicSort(ByRef dic As Scripting.Dictionary)
'
    Dim key         As Variant
    Dim varTmp()    As String
    Dim dicSize     As Long
    Dim lngCnt      As Long
'
    dicSize = dic.count
    '
    '   QuickSort関数 で varTmp(Int(i + j / 2))との比較が発生する
    '   ため配列のサイズは dicSize * 2 とする
    '
    ReDim varTmp(dicSize * 2, 2)
    '
    '   Dictionaryが空か、サイズが1以下であればソート不要
    '
    If dic Is Nothing Or dicSize < 2 Then
        Exit Sub
    End If
    '
    '   Dictionaryから二元配列に転写
    '
    lngCnt = 0
    For Each key In dic
        varTmp(lngCnt, 0) = key
        varTmp(lngCnt, 1) = dic(key)
        lngCnt = lngCnt + 1
    Next
    '
    '   クイックソート
    '
    Call QuickSort(varTmp, 0, dicSize - 1)
'
    dic.RemoveAll
'
    For lngCnt = 0 To dicSize - 1
        dic(varTmp(lngCnt, 0)) = varTmp(lngCnt, 1)
    Next
'
End Sub

'=================================================================
' 名 称 : QuickSort
' 機 能 : String型の二次元配列を受け取り
'       :これの一列目でクイックソートする
' パラメータ : targetVar() : 二次元配列
'            : min, max   : ソート対象
'=================================================================
Private Sub QuickSort(ByRef targetVar() As String, ByVal min As Long, ByVal max As Long)
'
    Dim i, j    As Long
    Dim tmp     As String
    Dim pivot   As String
    
    If min < max Then
        i = min
        j = max
        pivot = Med3(targetVar(i, 0), targetVar(Int(i + j / 2), 0), targetVar(j, 0))
        Do
            Do While StrComp(targetVar(i, 0), pivot) < 0
                i = i + 1
            Loop
            Do While StrComp(pivot, targetVar(j, 0)) < 0
                j = j - 1
            Loop
            If i >= j Then Exit Do
            
            tmp = targetVar(i, 0)
            targetVar(i, 0) = targetVar(j, 0)
            targetVar(j, 0) = tmp
        
            tmp = targetVar(i, 1)
            targetVar(i, 1) = targetVar(j, 1)
            targetVar(j, 1) = tmp
        
            i = i + 1
            j = j - 1
        
        Loop
        Call QuickSort(targetVar, min, i - 1)
        Call QuickSort(targetVar, j + 1, max)
        
    End If
End Sub

'=================================================================
' 名 称 : Med3
' 機 能 : String型のx, y, z を辞書順比較し二番目のものを返す
'=================================================================
Private Function Med3(ByVal x As String, ByVal y As String, ByVal z As String) As String
'
    If StrComp(x, y) < 0 Then
        If StrComp(y, z) < 0 Then
            Med3 = y
        ElseIf StrComp(z, x) < 0 Then
            Med3 = x
        Else
            Med3 = z
        End If
    Else
        If StrComp(z, y) < 0 Then
            Med3 = y
        ElseIf StrComp(x, z) < 0 Then
            Med3 = x
        Else
            Med3 = z
        End If
    End If
End Function