web-dev-qa-db-ja.com

Random.Range()から値を除外しますか?

Random.Range()を使用して値を生成している場合、範囲内の一部の値を除外する方法はありますか(たとえば、6から8ではなく1から20までの数値を選択してください)。

17
Dinovr

これを行う最良の方法は、お気に入りのジェネレーターを使用して1〜17の整数nを生成し、を使用して変換することです。

if (n > 5){
    n += 3;
}

1から20の間でサンプリングしてから値を破棄すると、統計的な異常が発生する可能性があります。 (たとえば、乱数ジェネレーターが線形合同法である場合、分散が高すぎます。試してみてください。)

13
Bathsheba

だからあなたは実際に17(20-3)異なる値

  [1..5] U [9..20]

そして、あなたはこのようなものを実装することができます:

  // Simplest, not thread-safe
  private static Random random = new Random();

  ...  

  int r = (r = random.Next(1, 17)) > 5
    ? r + 3
    : r;

一般的な(そして複雑な)ケースでは、すべての可能な値の配列を生成し、そこからアイテムを取得することをお勧めします。

  int[] values = Enumerable
    .Range(1, 100) // [1..100], but
    .Where(item => item % 2 == 1) // Odd values only
    .Where(item => !(item >= 5 && item <= 15)) // with [5..15] range excluded
    //TODO: Add as many conditions via .Where(item => ...) as you want
    .ToArray();

  ...

  int r = values[random.Next(values.Length)];
10
Dmitry Bychenko

はい、LINQでwhereステートメントを使用するだけです。

   var list = Enumerable.Range(1, 20).Where(a => a < 6 || a > 8).ToArray();

LINQを使用しない他の方法

        public IEnumerable RangeBetween()
        {
            foreach (var i in Enumerable.Range(1, 20))
            {
                if (i < 6 || i > 8)
                {
                    yield return i;
                }
            }
        }

編集:今、私は厳密なC#の質問ではないことがわかりました。 UnityRandomに影響します。しかし、完全な答えを得るには、上記のコードをEnumerable.Rangeとともに使用し、次にこれを使用して番号を生成すると思います。

list[Random.Next(list.Length)];
5

もう1つの方法は、有効な戻り値の配列を作成してから、ランダムに1つを選択することです。

void Main()
{
    var rng = new Random();
    var validValues = Enumerable.Range(1, 20).Except(new int[] {6, 7, 8}).ToArray();

    for (int i = 0; i < 25; i++)
    {
        Console.Write(validValues[rng.Next(0, validValues.Length)]);
        Console.Write(" ");
    }
}

編集:おっと!これはUnity3D用であるため、この例は適切でない可能性があることに気づきました。ただし、標準のRandomクラスを使用して機能します。

1
Chris Dunaway

Rが6〜8の範囲にある場合、これは別の乱数を選択します。

int r = 0;
do
{
    r = Random.Next(20);
} while (r >= 6 && r <= 8)
0
mbdavis