In this case, the MAX is only 5, so I could check the duplicates one by one, but how could I do this in a simpler way? For example, what if the MAX has a value of 20? Thanks.
int MAX = 5;
for (i = 1 , i <= MAX; i++)
{
drawNum[1] = (int)(Math.random()*MAX)+1;
while (drawNum[2] == drawNum[1])
{
drawNum[2] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
{
drawNum[3] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
{
drawNum[4] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[5] == drawNum[1]) ||
(drawNum[5] == drawNum[2]) ||
(drawNum[5] == drawNum[3]) ||
(drawNum[5] == drawNum[4]) )
{
drawNum[5] = (int)(Math.random()*MAX)+1;
}
}
The simplest way would be to create a list of the possible numbers (1..20 or whatever) and then shuffle them with
Collections.shuffle
. Then just take however many elements you want. This is great if your range is equal to the number of elements you need in the end (e.g. for shuffling a deck of cards).That doesn't work so well if you want (say) 10 random elements in the range 1..10,000 - you'd end up doing a lot of work unnecessarily. At that point, it's probably better to keep a set of values you've generated so far, and just keep generating numbers in a loop until the next one isn't already present:
Be careful with the set choice though - I've very deliberately used
LinkedHashSet
as it maintains insertion order, which we care about here.Yet another option is to always make progress, by reducing the range each time and compensating for existing values. So for example, suppose you wanted 3 values in the range 0..9. On the first iteration you'd generate any number in the range 0..9 - let's say you generate a 4.
On the second iteration you'd then generate a number in the range 0..8. If the generated number is less than 4, you'd keep it as is... otherwise you add one to it. That gets you a result range of 0..9 without 4. Suppose we get 7 that way.
On the third iteration you'd generate a number in the range 0..7. If the generated number is less than 4, you'd keep it as is. If it's 4 or 5, you'd add one. If it's 6 or 7, you'd add two. That way the result range is 0..9 without 4 or 6.
The most efficient, basic way to have non-repeating random numbers is explained by this pseudo-code. There is no need to have nested loops or hashed lookups:
Suppose first iteration generated random number 3 to start (from 0 - 19). This would make results[0] = mapping[3], i.e., the value 3. We'd then assign mapping[3] to 19.
In the next iteration, the random number was 5 (from 0 - 18). This would make results[1] = mapping[5], i.e., the value 5. We'd then assign mapping[5] to 18.
Now suppose the next iteration chose 3 again (from 0 - 17). results[2] would be assigned the value of mapping[3], but now, this value is not 3, but 19.
This same protection persists for all numbers, even if you got the same number 5 times in a row. E.g., if the random number generator gave you 0 five times in a row, the results would be: [ 0, 19, 18, 17, 16 ].
You would never get the same number twice.
This would be a lot simpler in
java-8
:Here is an efficient solution for fast creation of a randomized array. After randomization you can simply pick the
n
-th elemente
of the array, incrementn
and returne
. This solution has O(1) for getting a random number and O(n) for initialization, but as a tradeoff requires a good amount of memory if n gets large enough.There is another way of doing "random" ordered numbers with LFSR, take a look at:
http://en.wikipedia.org/wiki/Linear_feedback_shift_register
with this technique you can achieve the ordered random number by index and making sure the values are not duplicated.
But these are not TRUE random numbers because the random generation is deterministic.
But depending your case you can use this technique reducing the amount of processing on random number generation when using shuffling.
Here a LFSR algorithm in java, (I took it somewhere I don't remeber):
You could use one of the classes implementing the Set interface (API), and then each number you generate, use Set.add() to insert it.
If the return value is false, you know the number has already been generated before.