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