Выбирайте из диапазона, но исключайте определенные числа
Можно ли выбрать случайное число из заданного диапазона (1-90), но исключить определенные числа. Исключенные числа динамически создаются, но говорят, что они 3, 8 и 80.
Мне удалось создать генератор случайных чисел, но не смог определить какие-либо функции, которые позволили бы мне выполнить мои требования.
Random r = new Random();
this.num = r.Next(1, 90);
Номера, которые должны быть исключены, являются ранее сгенерированными числами. Итак, если случайное число равно единице, это будет добавлено в список исключенных номеров.
Ответы
Ответ 1
Используя некоторые удобные методы расширения здесь, вы можете создать диапазон чисел и выбирать случайным образом из этой ярости. Например, с помощью этих методов расширения:
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();
Ответ 2
Создайте контейнер, который содержит номера, которые вы не хотите:
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
Ответ 3
Не лучший выбор, но вы можете использовать цикл 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));
Ответ 4
Последнее обновление, которое подразумевает, что каждое значение можно выбрать только один раз, затрудняет задачу.
- Создайте набор значений в пределах диапазона.
- Случайно перемешать коллекцию.
- Чтобы "случайно" выбрать элемент, просто верните первый элемент в коллекции и удалите его из коллекции.
Ответ 5
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
}
}
Ответ 6
Убедитесь, что excludedNumbers
является HashSet
для лучшей производительности.
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();
Ответ 7
Это решение делает это в 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;
}
И тестовая функция, чтобы убедиться, что она работает (более 100 тыс. элементов)
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");
}