tags:

views:

6920

answers:

9

What is the best way to randomize the order of a generic list in C#? I've got a finite set of 75 numbers in a list I would like to assign a random order to, in order to draw them for a lottery type application.

thx!

+19  A: 

I think you're looking for a shuffling algorithm

Tom Ritter
+2  A: 

If you have a fixed number (75), you could create an array with 75 elements, then enumerate your list, moving the elements to randomized positions in the array. You can generate the mapping of list number to array index using the Fisher-Yates shuffle.

dmo
+2  A: 

I usually use:

var list = new List<T> ();
fillList (list);
var randomizedList = new List<T> ();
var rnd = new Random ();
while (list.Count != 0)
{
    var index = rnd.Next (0, list.Count);
    randomizedList.Add (list [index]);
    list.RemoveAt (index);
}
AlbertEin
A: 

A very simple approach to this kind of problem is to use a number of random element swap in the list.

In pseudo-code this would look like this:

do 
    r1 = randomPositionInList()
    r2 = randomPositionInList()
    swap elements at index r1 and index r2 
for a certain number of times
Aleris
One problem with this approach is knowing when to stop. It also has a tendency to exaggerate any biases in the pseudo-random number generator.
Mark Bessey
Yes. Highly inefficient. There is no reason to use an approach like this when better, faster approaches exist that are just as simple.
PeterAllenWebb
+5  A: 

The best way to shuffle a collection, like you want to, is to assign each element in the collection a random number, and then sort by that number. Jeff Atwood has more details.

Example code from his article:

var cards = Enumerable.Range(0, 51);
var shuffledcards = cards.OrderBy(a => Guid.NewGuid());
Gabe Moothart
This is not a great solution if performance is a concern. Sorting is an O(n*log(n)) operation. Shuffling only needs to be O(n). The 'shuffling algorithm' link shows a better way.
Neil Whitaker
Why would you order things by a guid instead of a plain random number? Granted there is an aspect of randomness to guids.
Adam Tegen
But in this case (75 numbers) performance is not a concern, and the algorithm is simpler/shorter than Fisher-Yates (which is what you're referring to?). With modern computers, developer cycles are usually more expensive than cpu cycles.
Gabe Moothart
+2  A: 
    public static List<T> Randomize<T>(List<T> list)
    {
        List<T> randomizedList = new List<T>();
        Random rnd = new Random();
        while (list.Count > 0)
        {
            int index = rnd.Next(0, list.Count); //pick a random item from the master list
            randomizedList.Add(list[index]); //place it at the end of the randomized list
            list.RemoveAt(index);
        }
        return randomizedList;
    }
Adam Tegen
+30  A: 

Shuffle any (I)List with an extension method based on the Fisher-Yates shuffle:

public static void Shuffle<T>(this IList<T> list)  
{  
    Random rng = new Random();  
    int n = list.Count;  
    while (n > 1) {  
        n--;  
        int k = rng.Next(n + 1);  
        T value = list[k];  
        list[k] = list[n];  
        list[n] = value;  
    }  
}

Usage:

List<Product> products = GetProducts();
products.Shuffle();

The code above uses the much criticised System.Random method to select swap candidates. It's fast but not as random as it should be. If you need a better quality of randomness in your shuffles use the random number generator in System.Security.Cryptography like so:

using System.Security.Cryptography;
...
public static void Shuffle<T>(this IList<T> list)
{
    RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
    int n = list.Count;
    while (n > 1)
    {
        byte[] box = new byte[1];
        do provider.GetBytes(box);
        while (!(box[0] < n * (Byte.MaxValue / n)));
        int k = (box[0] % n);
        n--;
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
    }
}

A simple comparison is available at: http://thegrenade.blogspot.com/2010/02/when-random-is-too-consistent.html

grenade
Nice! I love extension methods :D
Ben Daniel
Note that the performance of this is drastically lower on LinkedLists vs ArrayLists. Always be sure to send it a O(1) performance indexable array.
TheSoftwareJedi
+1  A: 

Extended method for IEnumerable:

public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
{
    Random rnd = new Random();
    return source.OrderBy<T, int>((item) => rnd.Next());
}
Denis
A: 

Thanks! Just what I was looking for

Britney
qstarin
Well, saying it as an answer is frowned upon. Saying it comments when something really saves your bacon isn't the end of the world.
Brian MacKay