一方、Array.Sortメソッドではこのような方法は使えません。 次の例では、Array.Sortメソッドに毎回異なる結果を返すIComparer<T>を指定することで配列をシャッフルしようとしています。 IComparer<T>は、Comparison<T>デリゲートと同様の大小関係を定義するメソッドをクラスに実装するためのインターフェイスです。 大小関係をランダムにすることで一見シャッフル出来るように思えますが、実際にArray.Sortメソッドを呼び出すと、場合によっては大小関係に矛盾が生じて例外がスローされるため、期待通りには動作しません。
Array.Sortメソッドで配列をシャッフルする(動作しない実装)
using System;
using System.Collections.Generic;
class Sample {
// ランダムに並べ替えるためのIComparer<int>を実装するクラス
class RandomComparer : IComparer<int> {
public int Compare(int x, int y)
{
// -1, 0, +1いずれかの値をランダムに返す
return rand.Next(-1, 2);
}
private Random rand = new Random();
}
static void Main()
{
var arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// シャッフル
Array.Sort(arr, new RandomComparer());
foreach (var val in arr) {
Console.Write("{0}, ", val);
}
Console.WriteLine();
}
}
実行結果の例 (大小関係に矛盾が生じなかった場合)
7, 8, 9, 4, 3, 1, 0, 2, 5, 6,
実行結果の例 (大小関係に矛盾が生じた場合)
ハンドルされていない例外: System.ArgumentException: IComparer.Compare() メソッドから矛盾する結果が返されたため、並べ替えできません。値をそれ自体と比較したときに等しい結果にならないか、またはある値を別の値と繰り返し比較したときに異なる結果が生じます。x: '0'、x の型: 'Int32'、IComparer: ''。 場所 System.Collections.Generic.GenericArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer) 場所 System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer) 場所 System.Array.Sort[T](T[] array, IComparer`1 comparer) 場所 Sample.Main()
その他のシャッフルの実装例については配列・コレクションのシャッフル、より適切な乱数の取得方法については乱数、IComparer<T>については大小関係の定義と比較を参照してください。