This question already has an answer here:
-
Is using Random and OrderBy a good shuffle algorithm?
12 answers
I'm trying to chose between 15 array values on a random base.
The problem i'm facing is the fact that i want a value to only be generated once during the program.
Once all 15 numbers are generated, the programs ends.
So my question is, how do you make sure a value is only generated once during the program.
int[] ImageValues = new int[15];
ImageValues[0] = 1;
ImageValues[1] = 2;
ImageValues[2] = 3;
ImageValues[3] = 4;
ImageValues[4] = 5;
ImageValues[5] = 6;
ImageValues[6] = 7;
ImageValues[7] = 8;
ImageValues[8] = 9;
ImageValues[9] = 10;
ImageValues[10] = 11;
ImageValues[11] = 12;
ImageValues[12] = 13;
ImageValues[13] = 14;
ImageValues[14] = 15;
Random randomize = new Random();
int initialValue = randomize.Next(0, 15);
int finalValue = ImageValues[initialValue];
First, you can also initialize your array when you declare it and the class should also have a Random
object so you can reuse it rather than creating a new one each time. So, perhaps in the ctor:
rand = new Random();
int[] ImageValues = new int[15]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
You can use a one-liner to randomize/shuffle it:
ImageValues = ImageValues.OrderBy(i => rand.Next()).ToArray();
This will work fine for many cases. The standard Fisher-Yates shuffle is accepted as fast and producing an unbiased order (when used correctly), so in some cases it may be better:
private void ArrayShuffle(int[] items)
{
// uses the Random var declared earlier
int tmp = 0;
int j = 0;
// hi to low, so the rand result is meaningful
for (int i = items.Count() - 1; i >= 0; i += -1)
{
j = rand.Next(0, i + 1); // NB max param is EXCLUSIVE
tmp = items[j];
// swap j and Card i
items[j] = items[i];
items[i] = tmp;
}
}
Either way, once the array is shuffled, you can use it to create a Stack
or Queue
by passing the array in the constructor:
int[] ImageValues = new int[15];
// ...
ArrayShuffle(ImageValues);
Stack<int> mystack = new Stack<int>(ImageValues);
You could just use the array and a variable pointing to the index to use. Using a collection type eliminates the need for that index var and the chance of a bug when it is/is not incremented. For something like a card game, it mimics dealing the next card from the top of the deck:
// ToDo:
// check myStack.Count() if times used is not controlled elsewhere
int nextVal = myStack.Pop();
A simple, efficient solution is this:
Say you have N elements from which to chose.
- You randomly pick an index from 0 to N-1 and remove the picked value
from the array.
- Copy the last element of the array to the
index you removed.
- Repeat steps 1-2 treating the array as if it's one element shorter, so on the second time you pick an index between 0 and N-2, then 0 and N-3 etc.
This guarantees that you can pick any K elements in exactly K iterations (so the algorithm is deterministic) and it guarantees a uniform distribution. One other benefit is that it doesn't require any additional memory allocation.
The easiest solution is to first create a list of your values... 1-15, then you randomly generate a number between 0 and 14.
You then take the value from that position and remove it from the list. Then you generate a new random number that is between 0 and 13. And so on, until you have removed all numbers.