【C#】リストからランダムに複数の要素を重複しないように取得する

2018年10月13日

リストから、ランダムに複数の要素を重複しないように選び出す処理を書く。

概要

選んだ要素を都度リストから削除しながら取り出す。

// Use this for initialization
void Start () {
  // 0,1,2,3,4,5,6,7,8,9のリストを作成
  List<int> list = new List<int>();
  for (int i = 0; i < 10; i++) {
    list.Add(i);
  }
 
  for (int i = 0; i < 5; i++) {
    selectRandomValue (list, 2);
  }
 
  for (int i = 0; i < 5; i++) {
    selectRandomValue (list,3);
  }
}
 
// 引数pCountの数だけ、リストからランダムに取得する
void selectRandomValue <T> (List<T> pList, int pCount = 0) {
  // 処理用のリストを作成
  List<T> tmpList = new List<T>();
  for (int i = 0; i < pList.Count; i++) {
    tmpList.Add (pList [i]);
  }
 
  // リストの数以上の回数ランダムに取得しないようにする
  if (pCount > pList.Count) {
    pCount = pList.Count;
  }
 
  // 結果を入れるリストを作成
  List<T> results = new List<T>();
 
  int count = pCount;
 
  // pCountの回数分ループ
  for (int j = 0; j < count; j++) {
    // 0〜pListリストの要素数の間でランダムに取得
    T result = tmpList[Random.Range(0, tmpList.Count)];
 
    // 取得した値をpListリストから削除
    tmpList.Remove(result);
 
    // 取得した値をresultsリストに追加
    results.Add(result);
  }
  logList(results, "results");
}
 
// リストの中身を出力するコード
void logList<T> (List<T> list, string name = "") {
  string str = "";
  if (name != "") {
    str += "["+name+"] ";
  }
  str += "list: ";
 
  for (int i = 0; i < list.Count; i++) {
    str += list [i]+" ";
  }
  Debug.Log (str);
}

結果

他にもやり方はある

今回はとりあえずこれでやってみましたが、リストをシャッフルして、先頭からn番目まで取得、というやり方もあるようです。
リストの数や、取得する数によって最適な処理は変わりそう。

参考