ランダムな値が入った配列の中から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;
}
}
}