What is an efficient way of generating N unique numbers within a given range using C#? For example, generate 6 unique numbers between 1 and 50. A lazy way would be to simply use Random.Next()
in a loop and store that number in an array/list, then repeat and check if it already exists or not etc.. Is there a better way to generate a group of random, but unique, numbers?
To add more context, I would like to select N random items from a collection, using their index.
thanks
For 6-from-50, I'm not too sure I'd worry about efficiency since the chance of a duplicate is relatively low (30% overall, from my back-of-the-envelope calculations). You could quite easily just remember the previous numbers you'd generated and throw them away, something like (pseudo-code):
However, this will break down as you move from 6-from-50 to 48-from-50, or 6-from-6, since the duplicates start getting far more probable. That's because the pool of available numbers gets smaller and you end up throwing away more and more.
For a very efficient solution that gives you a subset of your values with zero possibility of duplicates (and no unnecessary up-front sorting), Fisher-Yates is the way to go.
By simply selecting a random number from the pool, replacing it with the top number from that pool, then reducing the size of the pool, you get a shuffle without having to worry about a large number of swaps up front.
This is important if the number is high in that it doesn't introduce an unnecessary startup delay.
For example, examine the following bench-check, choosing 10-from-10:
You can see the pool reducing as you go and, because you're always replacing the used one with an unused one, you'll never have a repeat.
Using the results returned from that as indexes into your collection will guarantee that no duplicate items will be selected.
Take an array of 50 elements:
{1, 2, 3, .... 50}
Shuffle the array using any of the standard algorithms of randomly shuffling arrays. The first six elements of the modified array is what you are looking for. HTHFor large sets of unique numbers, put them in an List..
Then randomly generate a number from 1 to myInts.Count. Store the
myInt
value and remove it from the List. No need to shuffle the list nor look to see if the value already exists.This array will contain 5 random numbers from 0 to 4.
or
This array will contain 5 random numbers between 0 to 10.
generate unique random nos from 1 to 40 :
output confirmed :
sample output :
7 38 14 18 13 29 28 26 22 8 24 19 35 39 33 32 20 2 15 37
In case it helps anyone else, I prefer allocating the minimum number of items necessary. Below, I make use of a HashSet, which ensures that new items are unique. This should work with very large collections as well, up to the limits of what HashSet plays nice with.