連想配列を用いた無作為な並べ替え

↓ このようなお題をいただいたので、挑戦してみた。

データをランダムに並べ替えてください。

f:id:Infoment:20210508221959p:plain

今回の作戦は、こんな感じだ。

1. 並び変え用の通し番号を格納した、連想配列を作成する。

f:id:Infoment:20210508222400p:plain

2. 1~15の中から一つ、無作為に自然数を取得する。

取得は、RANDBETWEEN関数を使用する。
今回は、例えば「9」を取得したとする。
f:id:Infoment:20210508222712p:plain

3. 9番目のkeyの値「9」を用いて並べ替え。

元の配列の9番目の値を、並べ替え後の1番にセットする。
f:id:Infoment:20210508222925p:plain

4. 辞書の9番目を除去(REMOVE)する。

このとき、辞書の「何番目」は繰り上がるが、key情報で見た場合
9は欠番となる。
f:id:Infoment:20210508223150p:plain

5. 以降、2~4 の繰り返し。

ただし今度は1~15ではなく、1~14の中から一つ選ぶ。
今回は、例えば「11」を取得したとする。
f:id:Infoment:20210508223506p:plain
辞書の11番目のキー情報は「12」であるため、12番目の値を
並べ替え後の2番にセットする。
f:id:Infoment:20210508223644p:plain
これを3,4,5・・・と繰り返す。

実際のコード

Sub 並べ替え()
    ' 元データを配列に格納。
    Dim SrcArray As Variant
        SrcArray = Range("A1:A15")
    
    ' 並べ替え後のデータを格納する配列。
    Dim DstArray As Variant
    
    ' 元データの配列を格納することで、配列サイズを調整。
        DstArray = SrcArray
    
    ' 「何番目」を格納する辞書。
    Dim SortDict As Scripting.Dictionary
    Set SortDict = New Scripting.Dictionary
    Dim i As Long
    Dim iMax As Long: iMax = UBound(SrcArray)
    
    ' 「何番目」というキー情報のみ使用する。
    ' 従って、アイテム情報は不問。今回はキー=アイテムとした。
        For i = 1 To iMax
            SortDict(i) = i
        Next
    
    Dim temp As Long
        i = 1
        Do
            ' RandBetween関数で、「1~辞書のキーの個数」の範囲にある数を
            ' ランダムに求める。
            temp = WorksheetFunction.RandBetween(1, UBound(SortDict.Keys) + 1)
            
            ' 辞書のKeysは0始まりの配列として取得可能。tempは1始まりであるため、
            ' 1引いている。
            DstArray(i, 1) = SrcArray(SortDict.Keys(temp - 1), 1)
            
            ' 使用した「temp番目」を辞書から除去する。これにより、一度使用した
            ' 数は使われない。
            SortDict.Remove SortDict.Keys(temp - 1)
            
            If i = iMax Then
                Exit Do
            Else
                i = i + 1
            End If
        Loop
        
        Range("C1:C15") = DstArray
End Sub

元データを格納した配列と、並べ替え後の貼り付け先を引数にすれば、
もう少し汎用性が上がると思う。

参考まで。