How to organize Random without repetitions in Java?

There are numbers from 0 to 23. How do I make it so that when you click on the button, a random number is generated that does not occur at least 2 more times?

Author: default locale, 2019-05-13

5 answers

A method that does not require re-generation, ensuring that there is no repetition in each triple of consecutive numbers (i.e., I understand the task in the same way as Kromster in the comment)

Ideone with a limit of 8, not 24 (for easier control)

    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 version with output of the distribution histogram to control the uniformity

 3
Author: MBo, 2019-05-13 18:06:34

I understood your question as: "create a list of 24 random (from 0 to 24) numbers, so that each number does not repeat more than 2 times". And indeed-two sets. Each has unique numbers from 0 to 24. The maximum number of repetitions is 2 times per number. Just get the (res) values from here as needed.

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));
}
 3
Author: Miron, 2019-05-17 08:37:11

Implementation of what comrade @Kromster suggested:

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;
    }
}

The option is smarter, it does not have re-generation, and in general the code is clearer:

The sheet contains 24 possible values, we take a random one from the range 0-21 and move it to the end of the sheet. The disadvantage is that 2 numbers are excluded in advance, the situation can be slightly improved by placing the elements in the original array out of order.

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/

 1
Author: Stranger in the Q, 2019-05-13 18:07:06

Here is 1 more option Here, you enter your number in the Map as a key, and the number of its pins as a value. If you are allowed to repeat the number 2 times, put 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);
}
 0
Author: Dred, 2019-05-13 15:09:22

I can offer this option

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;
    }
}
 0
Author: Artem Konovalov, 2019-05-17 09:17:25