views:

307

answers:

4

I want to generate an array that has 144 number from 1->36 in random order (so each number is repeated 4 times). Can we use Enumerable.Repeat and Enumerable.Range to do that. If yes than please explain to me how?. Thanks you very much.

+8  A: 

Well, creating the sequence with all the numbers in is easy:

var items = from x in Enumerable.Range(1, 36)
            from y in Enumerable.Repeat(x, 4)
            select y;

Then you can just use ToArray to get it into an array and shuffle it. There are numerous questions about shuffling an array in C# on SO, such as this one. You could either use that code directly, or call ToArray and shuffle the array in place without yielding it at the end.

Jon Skeet
hey, that's more readable than my solution. +1
David Hedlund
and more elegant that my multiple Concat ;)
Thomas Levesque
thanks for the comment, but now I need to fill the generated array to an [9,16] array, can you suggest a good way for me?
A New Chicken
@A New Chicken: I suspect that using Buffer.BlockCopy will work for you... it's worth trying, anyway. (i.e. create the 2D array and use Buffer.BlockCopy to copy the 1D array into it.)
Jon Skeet
A: 
int[] numbers = Enumerable.Range(0, 144).Select(i => (i % 36)+1).OrderBy(g => Guid.NewGuid()).ToArray();
David Hedlund
Probably not important in this case, but this way of shuffling ends up being O(n log n) where it only needs to be O(n).
Jon Skeet
A: 
// Generate the list (not in random order)
var one_to_36 = Enumerable.Range(1, 36);
var lst = one_to_36.Concat(one_to_36).Concat(one_to_36).Concat(one_to_36).ToList();

// Randomize the list by swapping random elements
Random rnd = new Random();
for(int i = 0; i < lst.Count; i++)
{
    int i1 = rnd.Next(lst.Count);
    int i2 = rnd.Next(lst.Count);
    int tmp = lst[i1];
    lst[i1] = lst[i2];
    lst[i2] = tmp;
}
Thomas Levesque
Swapping random elements in this way doesn't give a good random distribution - there's a better way of shuffling a collection, as linked to in my answer.
Jon Skeet
I didn't realize that... thanks for the tip
Thomas Levesque
A: 
var seq = Enumerable.Range(0, 144);    
var all = seq.ToList();
var random = new Random();
var result = seq.Select(i => {
 var index = random.Next()%all.Count;
 var r = all[index] % 36 + 1; all.RemoveAt(index);
 return r;
}).ToList();
George Polevoy