I am trying to generate an array of random numbers. Each array entry will have a number between 0 and 31. I am trying to get the code to generate a random number and then check to see if that number exists in the array. If it does, it then generates a fresh random number and checks from the beginning again.
I thought I had it sussed with the code below:
public class HelloWorld{
public static void main(String []args){
int[] randArray = new int[10];
boolean firstNumber = true;
int randNum = 0;
for (int j=0; j < randArray.length; j++) {
if(firstNumber) {
randNum = (int)(Math.random() * 31 + 1);
randArray[j] = randNum;
firstNumber = false;
} else {
for (int k=0; k < randArray.length;) {
randNum = (int)(Math.random() * 31 + 1);
if(randArray[k] == randNum) {
k=0;
} else {
k++;
}
}
randArray[j] = randNum;
System.out.println(j);
}
}
System.out.println("-------");
for(int i=0; i < randArray.length; i++) {
System.out.println(randArray[i]);
}
}
}
But this is what it prints out:
1 2 3 4 5 6 7 8 9 ------- 25 17 19 20 24 4 26 30 6 24
As you can see, 24 is repeated twice. If I run the code again, you can see numbers being stored that are repeated.
Logically I cannot figure out why it is doing this. It may be something simple but I just can't see it.
I'm new to programming and this is something I thought I would test my knowledge with.
-
Could you elaborate on what you are trying to do? I think you are trying to shuffle all the numbers between 0 and 31 in an array. If so, there are better techniques.Bathsheba– Bathsheba2014年03月14日 08:42:08 +00:00Commented Mar 14, 2014 at 8:42
-
Is there a reason why you're using an array instead of a Set or some other data structure?leigero– leigero2014年03月14日 08:42:08 +00:00Commented Mar 14, 2014 at 8:42
-
Theoretically, a random number generator which always returns 42 is still random... If you want to ensure uniqueness of all numbers you'll have to check for yourself that a given number hasn't been generated yet.fge– fge2014年03月14日 08:42:22 +00:00Commented Mar 14, 2014 at 8:42
-
I am trying to create an array of unique random numbers. so from 0 - 9 in the array will contain a unique random generated number. No duplicates. I am using an array because I am getting to grips with the basics and I haven't come across other data structures yet (they have only been breifly mentioned). Would an Array be limited for this task?user1145909– user11459092014年03月14日 08:44:13 +00:00Commented Mar 14, 2014 at 8:44
-
fge - this is what I am trying to accomplish with the 2nd for loop. I want it to check the array to make sure that it hasn't appeared yet in the array, if so, then to generate a new random numberuser1145909– user11459092014年03月14日 08:45:00 +00:00Commented Mar 14, 2014 at 8:45
7 Answers 7
Your approach to generating unique random numbers is wrong, because when you get to the last number n in your array, you only have a 1/n chance to generate that particular number you need. And because you are working with random numbers, it may happen that you may wait a long time before you successfully generate the entire array. Furthermore, the time to generate the array is wildly unpredictable.
A far better way to do it would be to generate an array with an increasing sequence, and shuffle this array. That way, you are guaranteed to generate the array in O(n), and shuffle the array in O(n).
int arraySize=32;
int[] myArray= new int(arraySize);
for(int i=0;i<arraySize;i++) {
myArray[i]=i;
}
for(int i=0;i<arraySize;i++) {
int randNum = (int)(Math.random() * (arraySize-1));
int tmp=myArray[randNum];
myArray[randNum]=myArray[i];
myArray[i]=tmp;
}
2 Comments
You may try this code:
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
while (set.size() < 10) set.add((int)(Math.random() * 31) + 1);
Integer[] randArray = set.toArray(new Integer[0]);
for (int i = 0; i < randArray.length; i++) {
System.out.print(randArray[i] + " ");
}
System.out.println();
}
EXAMPLE OUTPUT:
2 3 4 21 6 7 10 29 12 14
6 Comments
Integer is already in the set, because a Set contains only distinct elements. The while-loop tries to add Integers till the number of distinct Integers is 10. Hence, you do not have to do the check by yourself. The Set does it for you.You are regenerating the random number each time you check on a row, rather than comparing the same number with all the array values in the inner loop.
Which you should be doing here is check the whole array against the same random number, and if you find a coincidence, set k to 0 and regenerate the random number to try again.
1 Comment
k=0; k < randArray.length loop. You check a new random number with one index in the randArray, instead of the same random number with each index. If you create the random number in the j=0; ... loop instead if should work. Also, you can get rid of the firstNumber stuff by just initialing randArray[0] to a new random number and loop from j=1; j < randArray.length.I'd use a Fisher-Yates shuffle to do this. It's the fastest way I know, at the expense of a little excess memory consumption. But it doesn't suffer from any retry overhead.
/*pseudocode; populate `arr` to taste. I'd be tempted to write it long-hand*/
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ..., 31};
/*Implement Fisher-Yates shuffle in its own scope block*/
{
Random random = new Random();
for (int i = arr.length - 1; i > 0; i--){
int r = random.nextInt(i + 1);
/*exhange r and i*/
int t = arr[r];
arr[r] = arr[i];
arr[i] = r;
}
}
/*ToDo - either rescale `arr` or just use the first 10 elements*/
Comments
Another Solution. Mark numbers which was generated.
public static void main(String[] args) {
int[] randArray = new int[10];
int randNum = 0;
boolean[] isPresented = new boolean[32];
for (int i = 0; i < randArray.length; ) {
randNum = (int)(Math.random() * 31 + 1);
if(!isPresented[randNum]){
randArray[i] = randNum ;
isPresented[randNum] = true;
i++;
}
}
System.out.println(Arrays.toString(randArray));
}
Comments
In the second for loop, you are generating a random number for every iteration of the loop. Change the loop as shown below.
else {
// generate a random number before the loop begins
randNum = (int)(Math.random() * 31 + 1);
for (int k=0; k < randArray.length;) {
if(randArray[k] == randNum) {
k=0;
// generate a random number only if the number exists in the array
randNum = (int)(Math.random() * 31 + 1);
} else {
k++;
}
}
randArray[j] = randNum;
System.out.println(j);
}
Comments
As far as I know the easiest and most efficient way of generating a (not very large) set of unique random numbers is (it is somewhat similar to method suggested by Bathsheba):
1) generate an ArrayList of unique sequential numbers to cover all required range
2) access the ArrayList using random index and moving (get and remove from the array) the entry at the index.
This way after ArrayList.size() iterations you will have a resulting array of unique random numbers.