从范围中选择但排除某些数字
是否可以从给定范围(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));
您的最新更新意味着每个值只能选择一次,这样可以轻松解决问题。
- 创建范围内的值集合。
- 随机洗牌。
- 要“随机”选择一个项目,只需返回集合中的第一个项目,然后将其从集合中删除。
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"); }