views:

146

answers:

5

What is the most elegant way to grab unique random numbers I ponder?

At the moment I need random unique numbers, I check to see if it's not unique by using a while loop to see if I've used the random number before.

So It looks like:

int n = getRandomNumber % [Array Size];

for each ( Previously used n in list)
    Check if I've used n before, if I have...try again.

There are many ways to solve this linear O(n/2) problem, I just wonder if there is a elegant way to solve it. Trying to think back to MATH115 Discrete mathematics and remember if the old lecturer covered anything to do with a seemingly trivial problem.

I can't think at the moment, so maybe once I have some caffeine my brain will suss it with the heightened IQ induced from the Coffee.

+5  A: 

If you want k random integers drawn without replacement (to get unique numbers) from the set {1, ..., n}, what you want is the first k elements in a random permutation of [n]. The most elegant way to generate such a random permutation is by using the Knuth shuffle. See here: http://en.wikipedia.org/wiki/Knuth_shuffle

Aaron
This will be practical only for a sufficiently small `n`. If `n` >= 2^32-1, for example, it would be impractical.
codekaizen
@codekaizen: I surmise from the OPs post that n is the size of an array, so this should be practical in that case.
GregS
@GregS: yes, in that case, it's true. The way I had read the question was that he wanted to generate sequences of arbitrary length.
codekaizen
A: 

Since you're imposing uniqueness, then a pseudorandom generator should be sufficient, which can be configured to not repeat for as long a sequence as you probably need. Eg, an LCG: if seed is uint32 and initially 0, then use (1664525 * seed) + 1013904223 for the next seed and take the low word for your unrepeated 16-bit result.

joe snyder
I don't think this answers the question. While the period of MT won't repeat (for 2^19937), numbers themselves will repeat, violating the questioner's constraint of number uniqueness.
codekaizen
You're still confusing the period of the random _sequence_ with the uniqueness of the numbers generated in that sequence. Numbers in the sequence from the MT repeat all the time.
codekaizen
How do you configure an LCG to not repeat numbers?
codekaizen
It's possible if you can factor the array size (which is easy if you know it in advance), but I suspect that is *much* harder than what @joe snyder had in mind.
GregS
+1  A: 

An n-bit Maximal Period Linear Shift Feedback Register (LFSR) will cycle through all of its (2^n -1) internal states before an internal state is repeated. A LFSR is a Maximal Period LFSR if and only if the polynomial formed from a tap sequence plus 1 is a primitive polynomial mod 2.

Thus, an n-bit Maximal Period LFSR will provide you with a sequence of (2^n - 1) unique random numbers, each one of them is n-bit long.

A LFSR is very elegant.

M.A. Hanin
The sequence won't, of course, be random...
Aaron
It would be pseudo-random, of course, and completely pre-determined. Anything which is generated using an algorithm, and not involving a special kind of hardware, would be PRNG. For a TRNG you must utilize some physical phenomenon which is considered random.
M.A. Hanin
It also won't solve the OPs problem, for which there is no reason to suspect an array length of 2^n - 1.
GregS
+3  A: 

grab unique random numbers I ponder?

  1. Make an array of N unique elements (integers in range 0..N-1, for example), store N as arraySize and initialArraySize (arraySize = N; initialArraySize = N)
  2. When random number is requested:
    2.1 if arraySize is zero, then arraySize = initialArraySize
    2.1 Generate index = getRandomNuber()%arraySize
    2.3 result = array[index]. Do not return result yet.
    2.2 swap array[index] with array[arraySize-1]. Swap means "exchange" c = array[index]; array[index] = array[arraySize-1]; array[arraySize-1] = c
    2.3 decrease arraySize by 1.
    2.4 return result.

You'll get a list of random numbers that won't repeat until you run out of unique values. O(1) complexity.

SigTerm
+2  A: 

In this blog post I discuss 5 different ways to generate a random subset. Each method is suitable for a different variation of the problem.

Eyal Schneider
nice article and analysis.
GregS
Cool, I Appreciate that link, very in depth, I wish had more time to properly explore it. Thanks Eyal
David van Dugteren