Как организовать Random без повторений на Java?

128
14 декабря 2020, 07:00

Есть числа с 0 по 23. Как сделать так, что бы при нажатии на кнопку генерировалось случайное число, которое не встречалось еще как минимум 2 раза?

Answer 1

Метод, не требующий повторной генерации, гарантирующий, что в каждой тройке последовательных чисел нет повтора (т.е. задачу я понимаю так же, как Kromster в комментарии)

Ideone с ограничением 8, а не 24 (для более лёгкого контроля)

    int n = 8;
    final Random rnd = new Random();
    int lastlast = rnd.nextInt(n);
    int last = (lastlast + 1 + rnd.nextInt(n - 1)) % n;
    for (int i = 0; i < 30; i++) {
        int r = (lastlast + 1 + rnd.nextInt(n - 2)) % n;
        if (r == last)
            r = (lastlast + n - 1) % n;
        lastlast = last;
        last = r;
        System.out.println(last);
    }

Python версия с выводом гистограммы распределения для контроля равномерности

Answer 2

Я понял твой вопрос как: "создать список из 24 рандомных(от 0 до 24) чисел, чтобы каждое число не повторялось более 2 раз". И действительно - два сета. В каждом уникальные числа от 0 до 24. Максимальное кол-во повторений - 2 раза на число. Просто доставайте отсюда(res) значения по необходимости.

ArrayList<Integer> first = new ArrayList<>(12);
ArrayList<Integer> second = new ArrayList<>(12);
int randTemp;
while(first.size()!=12){
    randTemp=getMyRandMethod();
    if(!first.contains(randTemp)){
          first.add(randTemp);
    }
} 
while(second.size()!=12){
    randTemp=getMyRandMethod();
    if(!second.contains(randTemp)){
          second.add(randTemp);
    };
}
ArrayList<Integer> res = new ArrayList<>(24);
for(int i=0;i<12;i++){
    res.add(first.get(i));
    res.add(second.get(i));
}
Answer 3

Реализация того что предложил товарищ @Kromster:

public class Rand24 extends Random {
    LinkedList<Integer> l = new LinkedList<>();
    public synchronized int next24() {
        int result;
        do result = nextInt(24);
        while (l.contains(result));
        l.add(result);
        if (l.size() == 3) l.removeFirst();
        return result;
    }
}

Вариант похитрее, в нем отсутствует повторная генерация и в целом код понятнее:

В листе лежат 24 возможных значения, берем случайное из диапазона 0-21 и перемещаем его в конец листа. Недостаток - заранее исключены 2 числа, ситуацию можно слегка улучшить расставив элементы в исходном массиве не по порядку.

public class Rand24_2 extends Random {
    List<Integer> values = IntStream.range(0, 24).boxed().collect(Collectors.toList());
    public synchronized int next24() {
        int rnd = values.remove(nextInt(values.size() - 2));
        values.add(rnd);
        return rnd;
    }
}

https://ideone.com/

Answer 4

Вот еще 1 вариант Здесь, вы в Map вносите свое число, как ключ, а в качестве значения количество его выводов. Если у вас допустимо, чтобы число повторялось 2 раза ставьте maxCount = 3

public void rand() {
    Map<Integer, Integer> map = new HashMap<>();
    int maxCount = 2;
    while (true) {
        int number = new Random().nextInt(23);
        if (!map.containsKey(number)) {
            map.put(number, 1);
            showNumber(number);
            break;
        } else {
            Integer value = map.get(number);
            if (value < maxCount) {
                showNumber(number);
            } else {
                value++;
                map.put(number, value);
            }
        }
    }
}
private void showNumber(int number) {
    System.out.println(number);
}
Answer 5

Могу предложить такой вариант

public final class RandomGenerator {
    private final int[] numbers;
    private int size;
    public RandomGenerator(int size) {
        numbers = new int[size];
        for (int i = 0; i < numbers.length; i++)
            numbers[i] = i;
        this.size = size;
    }
    private static void swap(int[] array, int i1, int i2) {
        int value = array[i1];
        array[i1] = array[i2];
        array[i2] = value;
    }
    public synchronized int getNumber() {
        if (size == 0)
            size = numbers.length;

        int index = ThreadLocalRandom.current().nextInt(size);
        int value = numbers[index];
        size--;
        swap(numbers, size, index);
        return value;
    }
}
READ ALSO
не отображаются кириллицы на jsp странице

не отображаются кириллицы на jsp странице

В приложении есть локализация en/ru, файл localizationproperties находится в папке webapp/WEB-INF/classes

153
Как при создании меню установить иконку из интернета?

Как при создании меню установить иконку из интернета?

изучаю Android (Java)Необходимо создать меню программно с иконками

117
Как найти элементы массива по индексу из другого массива и вывести обновлённый список во Vue

Как найти элементы массива по индексу из другого массива и вывести обновлённый список во Vue

Делаю фильтр по нажатию на кнопку должно найти у item категорию которая совпадает с категорией на кнопку, эти элементы оставить а остальные...

112
Передача значение input на другую страничку

Передача значение input на другую страничку

У меня есть две странички takenamehtml и givename

87