配列をシャッフルし、要素をランダムに並び替える方法を紹介します。ここでは配列を例にしていますが、コレクションでも同じようにできるでしょう。なおここで説明している事柄は、「Coding Horror: Shuffling」を参考にしています。
まず、Fisher-Yatesアルゴリズムによる方法を紹介します。この方法は非常に高速です。
'シャッフルする配列 Dim ary As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 'Fisher-Yatesアルゴリズムでシャッフルする Dim rng As New System.Random() Dim n As Integer = ary.Length While n > 1 n -= 1 Dim k As Integer = rng.Next(n + 1) Dim tmp As Integer = ary(k) ary(k) = ary(n) ary(n) = tmp End While
//シャッフルする配列 int[] ary = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //Fisher-Yatesアルゴリズムでシャッフルする System.Random rng = new System.Random(); int n = ary.Length; while (n > 1) { n--; int k = rng.Next(n + 1); int tmp = ary[k]; ary[k] = ary[n]; ary[n] = tmp; }
「Coding Horror: Shuffling」によると、上記の方法には2つの問題があるということです。1つは、Randomクラスが生成する配列が予測可能であり、安全ではないという点で、もう1つは、複雑であるという点です。これらの点を解消した方法として、OrderByメソッドで並び替え、Randomの代わりにGuidを使う方法が紹介されています。なお、OrderByメソッドは.NET Framework 3.5以降で使用でき、参照設定に「System.Core.dll」を追加する必要があります。OrderByメソッドについては、「配列やコレクション内の要素を並び替える」でも説明しています。
'Imports System.Linq 'がソースファイルの一番上に書かれているものとする 'シャッフルする配列 Dim ary As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 'シャッフルする Dim ary2 As Integer() = ary.OrderBy(Function(i) Guid.NewGuid()).ToArray()
//using System.Linq; //がソースファイルの一番上に書かれているものとする //シャッフルする配列 int[] ary = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //シャッフルする int[] ary2 = ary.OrderBy(i => Guid.NewGuid()).ToArray();