tags:

views:

216

answers:

5

Looking to shuffle four variables (trying to change the order they appear in on a multiple choice list).

I've been poking around for a while but I can't quite get my head around the logic, and looking up random shuffles in past questions gives super-detailed algorithms that are beyond my newbie skills (and the needs of this program I'm trying to write, I'd just like to make a multiple-choice image picker).

Ideally I'd like something that follows this pseudocode:

// int Answer1 = Random(min1 max4)

// int Answer2 = Random(min1 max4)

// int Answer3 = Random(min1 max4)

// int Answer4 = Random(min1 max4)

// If Answer 1 equals ANY of the other three, re-randomize Answer1 and loop.

// Loop through this cycle for all answers.

I'd post my current regular code, but frankly, it's garbage. :( This seems like a simple enough problem but I just can't get it right.

Thanks in advance!

+7  A: 

Shuffling - http://www.codinghorror.com/blog/archives/001008.html

Though, don't use a guid, use a random number:

//create only once, please
static readonly Random random = new Random();

and then:

var numbers = Enumerable.Range(1, 4);
var shuffle = numbers.OrderBy(a => random.NextDouble());
Kobi
+1 Concise. Smart.
John K
Curious why you wouldn't use a GUID.
Alastair Pitts
Personal preference, really. Looking around some more, this is better: http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm (in fact, the question is why *no*t to use this method!)
Kobi
Generating a GUID is more expensive and has some fixed components. If you want a pseudo-random number, then use a pseudo-random number. Period.
Joey
+3  A: 

Well, technically, who cares if it's just 4 numbers of 400 numbers. You should be using an implementation of Fisher-Yates shuffle. However, to make it easier to understand:

var possibleNumbers = new List<int>(Enumerable.Range(1, 4));
var result = new List<int>(4);
var rnd = new Random();
while (possibleNumbers.Count > 0) {
    int r = rnd.Next(possibleNumbers.Count);
    result.Add(possibleNumbers[r]);
    possibleNumbers.RemoveAt(r);
}

The algorithm demonstrated above is basically Fisher-Yates shuffle. In practice, you don't use two distinct lists to hold stuff. You simply choose a random element from the part of the array you haven't fixed yet and move it to its place. The beginning of the single list will be fixed elements while the end will be the possibilities.

Mehrdad Afshari
+1  A: 
        Random rand = new Random();
        List<int> choices = new List<int>() { 1, 2, 3, 4 };

        while (choices.Count > 0)
        {
            int index = rand.Next() % choices.Count;
            int choice = choices[index];
            Console.WriteLine(choice);
            choices.RemoveAt(index);
        }

edit - Instead of just printing the numbers, you could obviously add them to a new list.

Sapph
+1 Like the modulus to put the random number in range of the decreasing choices size.
John K
+3  A: 

I like this extension method:

static class IListExtensions {
    public static void Shuffle<T>(this IList<T> list, Random rg) {
        for (int i = list.Count; i > 1; i--) {
            int k = rg.Next(i);
            T temp = list[k];
            list[k] = list[i - 1];
            list[i - 1] = temp;
        }
    }
}

Then:

Random rg = new Random();
List<int> list = Enumerable.Range(1, 4).ToList();
list.Shuffle(rg);

Now list is a shuffling of {1, 2, 3, 4}.

The algorithm that I used here is the Fisher-Yates shuffle.

Jason
+1 Like the extension method and generic to sort different kinds of lists. Also can plug in algorithm of choice without affecting callers.
John K
@jdk: In particular, one could pass in an implementation of Mersenne Twister which has enough internal states to ensure that we have a truly unbiased shuffler for lists the size of a deck of playing cards (gamble gamble!). Or one could pass in a lava lamp shuffler (http://www.lavarnd.org/).
Jason
Efficient algorithm choice too - sorts in place, doesn't generate a second list.
John K