简体   繁体   中英

Exclude values from Random.Range()?

如果您使用Random.Range()生成值,是否有任何方法可以排除范围内的某些值(例如:选择1到20之间的数字,但不是6到8之间的数字)?

The best way to do this is to use your favourite generator to generate an integer n between 1 and 17 then transform using

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

If you sample between 1 and 20 then discard values you can introduce statistical anomalies. (For example, your variance will be too high if your random number generator is a linear congruential one: try it and see.)

So you actually want 17 (20 - 3) different values

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

and you can implement something like this:

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

  ...  

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

In general (and complicated) case I suggest generating an array of all possible values and then take the item from it:

  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)];

Yes, You simple use where statment in LINQ

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

Other way witout LINQ

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

EDIT: Now I see is not a strict C# question . It affect Unity and Random . But for complete answer I sugest You use code above with Enumerable.Range and next use this for generate the number:

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

Another way is to make an array of the valid return values and then randomly select one:

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(" ");
    }
}

EDIT: Oops! Just noticed this was for Unity3D so this example might not be appropriate. It works using the standard Random class, though.

This will pick a different random number if r is in the range 6-8 inclusive.

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

I'm going to throw in my 2 cents on the subject. Here is a complete class showing a method that generates a random number excluding numbers of your choice and how to use it.

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

public class test2 : MonoBehaviour {

    System.Random rand;
    int[] excludelist;
    void Start()
    {
         rand = new System.Random();
        excludelist = new int[] { 5,9,3};
        for(int i = 0; i<20;i++)
        {
            Debug.Log(MakeMeNumber(excludelist));
        }

    }
    private int MakeMeNumber(params int[] excludeList)
    {
        var excluding = new HashSet<int>(excludeList);
        var range = Enumerable.Range(1, 20).Where(i => !excluding.Contains(i));


        int index = rand.Next(0, 20 - excluding.Count);
        return range.ElementAt(index);
    }
}

I've created an asset designed exactly for that case (it's paid).

It simply contains a few useful functions that generate a random number from the given intervals (between X and Y excluding Z, for example).

Your example (between 1 and 20, but excluding 6 to 8) would be covered by the third function, RandomExclude.RandomInt (int, int, Vector2). The first int is the lowest possible value, the second int is the highest and the Vector2 is the interval that we exclude. In your case it'd look like that:

int ourOutcome = RandomExclude.RandomInt (1, 20, new Vector2 (6, 8));

The asset contains a few more similar functions, they let you generate an int excluding one number, excluding a few numbers or excluding a few intervals.

All detailed instructions of implementation are already covered in the asset itself, so don't worry.

https://assetstore.unity.com/packages/tools/input-management/random-exclude-133786

Feel free to try it!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM