1

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];
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
user24028
  • 39
  • 1
  • 7
  • 1
    one way would be to shuffle the array, store it in a Stack and just Pop() then one at a time – Ňɏssa Pøngjǣrdenlarp Jan 03 '15 at 01:35
  • This is a standard "shuffle" algorithm. I am positive it's been answered before on SO (probably many times). Looking for the duplicate now... – Peter Duniho Jan 03 '15 at 01:52
  • @PeterDuniho There are almost two questions here, one is how to do the shuffle (which is certainly a duplicate). The other is how to only use each value once, which plutonix's answer handles – BradleyDotNET Jan 03 '15 at 01:58
  • @BradleyDotNET: Given a shuffle, "only use each value once" is trivial: just iterate through the shuffled array. I fail to see the value in a question that, given the duplicate, amounts to "iterate through a shuffled array". – Peter Duniho Jan 03 '15 at 01:59
  • @PeterDuniho Good point, I hadn't thought about the obviously easy way to accomplish that! – BradleyDotNET Jan 03 '15 at 02:07

3 Answers3

2

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();
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
0

A simple, efficient solution is this:

Say you have N elements from which to chose.

  1. You randomly pick an index from 0 to N-1 and remove the picked value from the array.
  2. Copy the last element of the array to the index you removed.
  3. 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.

Malt
  • 28,965
  • 9
  • 65
  • 105
-1

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.

Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
  • That's a problematic algorithm. You have no way of knowing how many iterations will be needed to pick all elements. It might be fine for 15 elements, but imagine the same thing with 1,000,000 elements. Once you've picked 999,999 elements, there's one chance in a million of picking the last one at each iteration. That might take a while.. – Malt Jan 03 '15 at 01:45
  • @Matt - True, and you're also right about the other approach. – Erik Funkenbusch Jan 03 '15 at 01:51