C#である数列の内容を重複せずランダムに取り出す

前回書いたC#の乱数の作成を利用してある数列の内容を重複せずにランダムに取り出す方法を紹介したいと思います。

「同じ数字は出したくない」という場面で使用できるかと思います。

この実装を使用した場合の使用方法は以下の通りです。

public static void Main(string[] args)
{
    // リストの0~3を重複せずランダムに取り出す
    foreach (int item in RandomGet(new List<int>() { 0, 1, 2, 3 }))
    // foreach (int item in Random(new int[] { 0, 1, 2, 3 }) // 配列の指定でもOK
    {
        Console.WriteLine(item);
        // > 2
        // > 3
        // > 1
        // > 0
    }
}

このように、入力した数列を重複せずに取得することができます。

実装内容

上記で使用したRandomGetメソッドの実装内容は以下の通りです。

public static IEnumerable<T> RandomGet<T>(IEnumerable<T> list)
{
    var tempList = new List<T>(list); // 入力をリストにコピーする
    
    var r = new Random(); // 値を取り出すときに乱数を使用する

    while (tempList.Count() != 0)
    {
        int index = r.Next(0, tempList.Count);

        T value = tempList[index];
        tempList.RemoveAt(index);

        yield return value;
    }
}

引数は IEnumerabel\<T> 型としてC#のリスト的な型を広く受け入れられるように宣言します。

次に、以降の操作で扱いやすいようにListに引数をコピーしています。そして乱数でリストのインデックスを指定しつつ、指定した要素をリストから取り除く操作をリストの内容が空になるまで繰り返しています。

今回は int 型の配列でしたが、任意の型を指定できるので自作のオブジェクト型の配列からランダムに要素を取り出すこともできます。

簡単ですが以上です。