Генерация уникальных случайных чисел в Java - PullRequest
68 голосов
/ 14 ноября 2011

Я пытаюсь получить случайные числа от 0 до 100. Но я хочу, чтобы они были уникальными, а не повторялись в последовательности. Например, если я получил 5 номеров, они должны быть 82,12,53,64,32, а не 82,12,53,12,32 Я использовал это, но он генерирует те же числа в последовательности.

Random rand = new Random();
selected = rand.nextInt(100);

Ответы [ 17 ]

121 голосов
/ 14 ноября 2011
  • Добавьте каждое число в диапазоне последовательно в структуру список .
  • Shuffle it.
  • Возьмите первый 'n'.

Вот простая реализация.Это напечатает 3 уникальных случайных числа из диапазона 1-10.

import java.util.ArrayList;
import java.util.Collections;

public class UniqueRandomNumbers {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        for (int i=1; i<11; i++) {
            list.add(new Integer(i));
        }
        Collections.shuffle(list);
        for (int i=0; i<3; i++) {
            System.out.println(list.get(i));
        }
    }
}

Первая часть исправления с оригинальным подходом, как отметил Марк Байерс в удаленном ответе, заключается виспользуйте только один экземпляр Random.

Вот почему цифры одинаковы.Экземпляр Random засеивается текущим временем в миллисекундах.Для определенного начального значения случайный экземпляр будет возвращать точно такую ​​же последовательность псевдослучайных чисел.

42 голосов
/ 27 июля 2015

В Java 8+ вы можете использовать ints метод Random, чтобы получить IntStream случайных значений, а затем distinct и limit для уменьшения потока до числа уникальных случайных значений.

ThreadLocalRandom.current().ints(0, 100).distinct().limit(5).forEach(System.out::println);

Random также имеет методы, которые создают LongStream s и DoubleStream s, если они вам нужны.

Если вы хотите, чтобы все (или большое количество) чисел в диапазоне в случайном порядке, было бы более эффективно добавить все числа в список, перемешать его и взять первые n, потому что приведенный выше пример в настоящее время реализуется путем генерации случайных чисел в запрошенном диапазоне и передачи их через набор (аналогично ответу Роба Килти ), что может потребовать генерации гораздо большего, чем сумма, переданная для ограничения, поскольку вероятность генерации новый уникальный номер уменьшается с каждым найденным. Вот пример другого способа:

List<Integer> range = IntStream.range(0, 100).boxed()
        .collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(range);
range.subList(0, 99).forEach(System.out::println);
18 голосов
/ 14 ноября 2011
  1. Создайте массив из 100 чисел, затем рандомизируйте их порядок.
  2. Разработайте генератор псевдослучайных чисел с диапазоном 100.
  3. Создайте логический массив 100элементы, а затем установить элемент true, когда вы выбираете этот номер.Когда вы выбираете следующее число, проверьте массив и повторите попытку, если установлен элемент массива.(Вы можете создать простой в очистке логический массив с массивом long, в котором вы перемещаетесь и маскируете для доступа к отдельным битам.)
16 голосов
/ 14 ноября 2011

Используйте Collections.shuffle() на всех 100 числах и выберите первые пять, как показано здесь .

11 голосов
/ 21 февраля 2014

Я чувствую, что этот метод стоит упомянуть.

   private static final Random RANDOM = new Random();    
   /**
     * Pick n numbers between 0 (inclusive) and k (inclusive)
     * While there are very deterministic ways to do this,
     * for large k and small n, this could be easier than creating
     * an large array and sorting, i.e. k = 10,000
     */
    public Set<Integer> pickRandom(int n, int k) {
        final Set<Integer> picked = new HashSet<>();
        while (picked.size() < n) {
            picked.add(RANDOM.nextInt(k + 1));
        }
        return picked;
    }
8 голосов
/ 05 июля 2012

Я пересмотрел ответ Ананда, чтобы использовать не только уникальные свойства набора, но и использовать логическое ложное значение, возвращаемое set.add(), когда не удается добавить в набор.

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class randomUniqueNumberGenerator {

    public static final int SET_SIZE_REQUIRED = 10;
    public static final int NUMBER_RANGE = 100;

    public static void main(String[] args) {
        Random random = new Random();

        Set set = new HashSet<Integer>(SET_SIZE_REQUIRED);

        while(set.size()< SET_SIZE_REQUIRED) {
            while (set.add(random.nextInt(NUMBER_RANGE)) != true)
                ;
        }
        assert set.size() == SET_SIZE_REQUIRED;
        System.out.println(set);
    }
}
6 голосов
/ 13 марта 2018

Я сделал это так.

    Random random = new Random();
    ArrayList<Integer> arrayList = new ArrayList<Integer>();

    while (arrayList.size() < 6) { // how many numbers u need - it will 6
        int a = random.nextInt(49)+1; // this will give numbers between 1 and 50.

        if (!arrayList.contains(a)) {
            arrayList.add(a);
        }
    }
4 голосов
/ 04 июля 2012

Это будет работать для генерации уникальных случайных чисел ................

import java.util.HashSet;
import java.util.Random;

public class RandomExample {

    public static void main(String[] args) {
        Random rand = new Random();
        int e;
        int i;
        int g = 10;
        HashSet<Integer> randomNumbers = new HashSet<Integer>();

        for (i = 0; i < g; i++) {
            e = rand.nextInt(20);
            randomNumbers.add(e);
            if (randomNumbers.size() <= 10) {
                if (randomNumbers.size() == 10) {
                    g = 10;
                }
                g++;
                randomNumbers.add(e);
            }
        }
        System.out.println("Ten Unique random numbers from 1 to 20 are  : " + randomNumbers);
    }
}
2 голосов
/ 21 сентября 2015

Я пришел сюда из другого вопроса, который был дубликатом этого вопроса ( Генерация уникального случайного числа в Java )

  1. Храните от 1 до 100 чисел в массиве.

  2. Генерирует случайное число от 1 до 100 в качестве позиции и возвращает массив [position-1], чтобы получить значение

  3. Как только вы используете число в массиве, пометьте значение как -1 (нет необходимости поддерживать другой массив, чтобы проверить, используется ли уже этот номер)

  4. Если значение в массиве равно -1, снова получить случайное число, чтобы получить новое местоположение в массиве.

2 голосов
/ 04 мая 2014

Один умный способ сделать это - использовать экспоненты примитивного элемента в модуле.

Например, 2 - это примитивный корневой мод 101, что означает, что полномочия 2 мода 101 дают вам неповторяющаяся последовательность, которая видит каждое число от 1 до 100 включительно:

2^0 mod 101 = 1
2^1 mod 101 = 2
2^2 mod 101 = 4
...
2^50 mod 101 = 100
2^51 mod 101 = 99
2^52 mod 101 = 97
...
2^100 mod 101 = 1

В коде Java вы должны написать:

void randInts() {
int num=1;
for (int ii=0; ii<101; ii++) {
    System.out.println(num);
    num= (num*2) % 101;
    }
}

Найти первообразный корень для определенного модуля может быть сложно,но функция "primroot" в Maple сделает это за вас.

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