Подтвердить что ты не робот

Как я могу генерировать случайное число в пределах диапазона, но исключать некоторые?

Как я могу генерировать случайное число в пределах диапазона, но исключать некоторые, не продолжая генерировать и проверять, является ли сгенерированное число одним из тех, которые я хочу исключить?

4b9b3361

Ответ 1

Одним из возможных решений без регенерации случайным каждый раз является использование следующего алгоритма:

public int getRandomWithExclusion(Random rnd, int start, int end, int... exclude) {
    int random = start + rnd.nextInt(end - start + 1 - exclude.length);
    for (int ex : exclude) {
        if (random < ex) {
            break;
        }
        random++;
    }
    return random;
}

Этот метод может быть вызван с помощью ссылки на массив, например

int[] ex = { 2, 5, 6 };
val = getRandomWithExclusion(rnd, 1, 10, ex)

или путем непосредственного ввода чисел в вызов:

val = getRandomWithExclusion(rnd, 1, 10, 2, 5, 6)

Он генерирует случайное число (int) между start и end (оба включительно) и не дает вам никакого числа, которое содержится в массиве exclude. Все остальные числа встречаются с равной вероятностью. Обратите внимание, что должны сохраняться следующие ограничения: exclude сортируется по возрастанию и все числа находятся в пределах диапазона, и все они взаимно различаются.

Ответ 2

/**
 * @param start start of range (inclusive)
 * @param end end of range (exclusive)
 * @param excludes numbers to exclude (= numbers you do not want)
 * @return the random number within start-end but not one of excludes
 */
public static int nextIntInRangeButExclude(int start, int end, int... excludes){
    int rangeLength = end - start - excludes.length;
    int randomInt = RANDOM.nextInt(rangeLength) + start;

    for(int i = 0; i < excludes.length; i++) {
        if(excludes[i] > randomInt) {
            return randomInt;
        }

        randomInt++;
    }

    return randomInt;
}

Идея состоит в том, чтобы уменьшить диапазон, в котором случайное число генерируется до разницы между начальным и конечным минусом числа чисел в пределах этого диапазона, которые исключены.

Итак, вы получаете длину диапазона, которая совпадает с количеством возможных допустимых чисел. Другими словами: вы удалили все отверстия из диапазона.

После генерации случайного числа вы должны поместить "дыры" обратно в диапазон. Это может быть достигнуто путем увеличения сгенерированного числа до тех пор, пока не будут исключены числа, меньшие или равные сгенерированным. Нижние номера исключений - это "дыры" в диапазоне до сгенерированного числа. И сгенерированное число смещается вправо для каждого отверстия до этого числа.

Ответ 3

Лучший подход, который вы можете использовать для рандомизации чисел, за исключением некоторых, - это выбор номеров, которые вы хотите в первую очередь, а затем случайным образом выбираете выбранные числа. Например, в псевдокоде:

List<Number> numbers;

numbers.add(1);
numbers.add(2);
numbers.add(3);
//You can do a "for" without adding the excluded numbers..

//Then, your randomizer could be...

public Number getRandoNumber() {
    int index = Random.get(0, numbers.size());
    return numbers.get(index);
}

Теперь вам не нужно проверять, разрешен ли "сгенерированный номер" или нет, потому что он вообще не существует.

Если вы не хотите, чтобы они повторялись, вы можете сделать что-то вроде:

Collections.shuffle(numbers);

public Number getRandomNotRepeat() {
     if(numbers.size() == 0)
        throw new RuntimeException("No more numbers");

       Number n = numbers.get(0);
       numbers.removeFirst();

       return n;
}

Это все псевдокод, не копируйте и не вставляйте!

Ответ 4

Я думаю, что дополнительный вопрос: каковы цифры, которые вы хотите выразить? Представляют ли они какой-то диапазон или являются ли они полностью случайными?

Если бы это был диапазон чисел, которые вы хотите игнорировать, вы можете сгенерировать свои случайные числа из нескольких наборов, которые представляют только действительные числа:

rand(1,9);
rand(15,19);
rand(22,26);

таким образом вы уверены, что никогда не будете выбирать исключенные: < 0,10,11,12,13,14,20,21, > 27

Затем, когда вы получите 3 номера, вы можете случайно выбрать один из них.

Если исключенные цифры повсюду, то я боюсь, что вам придется каждый раз проверять его на какую-то коллекцию исключенных номеров.

Ответ 5

Создайте карту, которая выводит произвольную функцию без ограничения диапазона и сопоставляет ее с диапазоном, который вы хотите с ограничениями.

Например, если я хочу случайный int от 1 до 10, но никогда не могу сделать что-то вроде этого:

int i = rand(1, 9);
if i>=7
  i++;
return i;

Пока вы гарантируете, что ваше отображение равно 1:1, вы можете избежать искажения случайности вашей функции rand.

Ответ 6

В зависимости от того, насколько велик список случайных чисел, которые вы исключаете, я бы просто сгенерировал ваши номера и проверил, находится ли он в массиве исключенных номеров - если это так, просто отбросьте его. Я знаю, что вы не хотите проверять каждый раз, но я не могу придумать другой способ, кроме указания диапазонов явно, и если у вас есть более 5 номеров, которые вы исключаете, это может быть немного хуже.

Ответ 7

Что-то, что могло бы работать и применялось как к int, так и к двойным числам, могло бы быть следующим:

public int getRandomNumberWithExclusion( int start, int end )
{
  Random r = new Random();
  int result = -1;

  do
  {
      result = start + r.nextInt( end - start );
  }//do
  while( !isAllowed( result ) );

  return result;

}//met

private boolean isAllowed( int number )
{
   //your test for restricted values here
}//met

С уважением,  Stéphane

Ответ 8

Исключить числа должны быть с параметром диапазона

private int GiveMeANumber(int range,int... exclude)
{

    Set<Integer> integers=new HashSet<>();
    int count=range;

    for(int i=0;i<count;i++)
        integers.add(i);

    integers.removeAll(Arrays.asList(exclude));


    int index = new Random().nextInt(range - exclude.length);

    count=0;

    for (int value:integers){
        if(count==index)
            return value;

        count++;
    }


    return 0;
}