LoginSignup
1
1

More than 3 years have passed since last update.

配列の中から条件に当てはまる要素をランダムに1つ返す

Posted at

ランダムな値が入った配列の中から10以下の値のうちどれか一つをランダムで返すような処理をC#で書く。やりかたはいくつかあるので複数パターン列挙する。

int[] array = { 10, 2, 33, 40, 1, 3, 34, 21, 30, 5, 73, 41, 0 };

なお指定の範囲の整数xを返すランダム関数を以下のように定義しておく。(min <= x < max)

int Rand(int min, int max)

1.簡潔な方法

フィルタリングした配列からランダムで値を取得する。

int[] newArray = array.Where(filter).ToArray();
int result = newArray[Rand(0, newArray.Count())];

2.シャッフルを使う方法

上の方法では ToArray したときに新しい配列が生成されてしまうので、もとの配列を書き換えることでメモリが確保されないようにする。
シャッフルして条件に当てはまる最初の要素を返す。C#にはランダムに並べ替えるシャッフル関数がないので、まずはシャッフル関数を定義する。
シャッフル関数は余計なバッファを使わず計算量がO(n)ですむFisher–Yatesのアルゴリズムを使う。

void Shuffle(int[] array)
{
    for (int i = 0; i < array.Length - 1; i++)
    {
        int j = Rand(i, array.Length);
        int v = array[i];
        array[i] = array[j];
        array[j] = v;
    }
}
int result;
Shuffle(array);
foreach (var v in array)
{
    if (v <= 10)
    {
        result = v;
        break;
    }
}

3.シャッフルを用いたもう少し効率のいい方法

シャッフルしながら条件に当てはまる要素を探す。

for (int i = 0; i < array.Length - 1; i++)
{
    int j = Rand(i, array.Length);
    int v = array[j];
    if (v <= 10)
    {
        result = v;
        break;
    }
    array[j] = array[i];
    array[i] = v;
}

4.もとの配列を変更しない方法

メモリも確保したくないし、もとの配列の順番が変わってしまうのが困る場合の方法。
条件に当てはまる値の総数を数えて、何番目に見つかる値を採用するかランダムに決める。

int result;
int count = 0;
foreach (int v in array)
{
    if (v <= 10)
    {
        count++;
    }
}
int index = Rand(0, count);
foreach (int v in array)
{
    if (v <= 10)
    {
        index--;
        if (index < 0)
        {
            result = v;
            break;
        }
    }
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1