从范围中选择但排除某些数字

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

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

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

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

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

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

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

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

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

 var excludedNumbers = new List { 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 

可能不是最好的选择,但您可以使用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)); 

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

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

确保excludedNumbers是一个HashSet以获得最佳性能。

 var random = new Random(); var exludedNumbers = new HashSet(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(); 

这个解决方案在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; } 

并有一个测试function,以确保它的工作原理(超过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"); }