【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番目まで取得、というやり方もあるようです。
リストの数や、取得する数によって最適な処理は変わりそう。

参考