从范围中选择但不包括某些数字

时间:2013-12-05 14:04:58

标签: c# wpf random numbers range

是否可以从给定范围(1-90)中选择一个随机数,但不包括某些数字。排除的数字是动态创建的,但可以说它们分别为3,8和80.

我已设法创建随机数生成器但无法识别任何能够满足我要求的函数。

Random r = new Random();
this.num = r.Next(1, 90);

要排除的数字是先前生成的数字。因此,如果随机数为1,则会将其添加到排除的数字列表中。

7 个答案:

答案 0 :(得分:8)

使用一些方便的扩展方法here,您可以创建一系列数字并从该愤怒中随机选择。例如,使用这些扩展方法:

public static T RandomElement(this IEnumerable<T> enumerable)
{
    return enumerable.RandomElementUsing(new Random());
}

public static T RandomElementUsing(this IEnumerable<T> enumerable, Random rand)
{
    int index = rand.Next(0, enumerable.Count());
    return enumerable.ElementAt(index);
}

您可以将这些应用于过滤的数字范围:

var random = Enumerable.Range(1, 90).Except(arrayOfRemovedNumbers).RandomElement();

答案 1 :(得分:5)

创建一个容纳您不想要的数字的容器:

var excludedNumbers = new List<int> { 1, 15, 35, 89 };

然后使用类似的东西:

Random random = new Random();

int number;

do
{
   number = r.Next(1, 90);
} while (excludedNumbers.Contains(number));

// number is not in the excluded list now

答案 2 :(得分:4)

可能不是最佳选择,但您可以使用while循环来检查您不想要的数字

Random r = new Random();
this.num = r.Next(1, 90);
do
{
    this.num = r.Next(1, 90);
}  
while (this.num == 3 || this.num == 8 || this.num == 90);

对于大量数字,您可以使用数组或列表并循环遍历它们

int[] exclude = { 3, 8, 90, 11, 24 };
Random r = new Random();
this.num = r.Next(1, 90);
do
{
    this.num = r.Next(1, 90);
}
while (exclude.Contains(this.num));

答案 3 :(得分:3)

您的最新更新,这意味着每个值只能选择一次,这样可以轻松解决问题。

  1. 创建范围内的值集合。
  2. 随机洗牌。
  3. 要“随机”选择一个项目,只需返回该集合中的第一个项目,然后将其从该集合中删除。

答案 4 :(得分:2)

Random r = new Random();
this.num = r.Next(1, 90);

int excluded[] = new int[] { 3,8,80 }; // list any numbers in this array you want to exclude

for (int i = 0; i < excluded.Length; i++)
{
    if (this.num == excluded[i])
    {
        this.num = r.Next(1, 90); // or you can try doing something else here
    }
}

答案 5 :(得分:2)

确保excludedNumbersHashSet以获得最佳效果。

var random = new Random();
var exludedNumbers = new HashSet<int>(new int[] { 3, 8, 80});
var randomNumber = (from n in Enumerable.Range(int.MinValue, int.MaxValue)
                    let number = random.Next(1, 90)
                    where !exludedNumbers.Contains(number)
                    select number).First();

答案 6 :(得分:1)

此解决方案在O(n)最坏的情况下执行此操作,其中n是排除列表和常量内存。代码有点长,但如果您:

可能是相关的
  • 可能有大量排除列表
  • 需要多次运行
  • 范围广

它保留了随机分布,因为它实际上会跳过排除列表,并在不包括该集合的范围内生成一个随机数。

这是实施:

private static int RandomInRangeExcludingNumbers(Random random, int min, int max, int[] excluded)
{
    if (excluded.Length == 0) return random.Next(min, max);

    //array should be sorted, remove this check if you
    //can make sure, or sort the array before using it
    //to improve performance. Also no duplicates allowed
    //by this implementation
    int previous = excluded[0];
    for (int i = 1; i < excluded.Length; i++)
    {
        if (previous >= excluded[i])
        {
            throw new ArgumentException("excluded array should be sorted");
        }
    }

    //basic error checking, check that (min - max) > excluded.Length
    if (max - min <= excluded.Length)
        throw new ArgumentException("the range should be larger than the list of exclusions");

    int output = random.Next(min, max - excluded.Length);


    int j = 0;
    //set the start index to be the first element that can fall into the range
    while (j < excluded.Length && excluded[j] < min) j++;

    //skip each number occurring between min and the randomly generated number
    while (j < excluded.Length && excluded[j] <= output)
    {
        j++;
        output++;
        while (excluded.Contains(output))
            output++;
    }

    return output;
}

测试功能以确保其有效(超过100k元素)

private static void Test()
{
    Random random = new Random();
    int[] excluded = new[] { 3, 7, 80 };
    int min = 1, max = 90;

    for (int i = 0; i < 100000; i++)
    {
        int randomValue = RandomInRangeExcludingNumbers(random, min, max, excluded);

        if (randomValue < min || randomValue >= max || excluded.Contains(randomValue))
        {
            Console.WriteLine("Error! {0}", randomValue);
        }
    }
    Console.WriteLine("Done");
}