Most efficient way to randomly "sort" (Shuffle) a list of integers in C#
A good linear-time shuffling algorithm is the Fisher-Yates shuffle.
One problem you'll find with your proposed algorithm is that as you near the end of the shuffle, your loop will spend a lot of time looking for randomly chosen elements that have not yet been swapped. This may take an indeterminate amount of time once it gets to the last element to swap.
Also, it looks like your algorithm will never terminate if there are an odd number of elements to sort.
static Random random = new Random();
public static IEnumerable<T> RandomPermutation<T>(IEnumerable<T> sequence)
{
T[] retArray = sequence.ToArray();
for (int i = 0; i < retArray.Length - 1; i += 1)
{
int swapIndex = random.Next(i, retArray.Length);
if (swapIndex != i) {
T temp = retArray[i];
retArray[i] = retArray[swapIndex];
retArray[swapIndex] = temp;
}
}
return retArray;
}
modified to handle lists or other objects implementing IEnumerable
We can make an extension method out of this to get a Random enumerator for any IList collection
class Program
{
static void Main(string[] args)
{
IList<int> l = new List<int>();
l.Add(7);
l.Add(11);
l.Add(13);
l.Add(17);
foreach (var i in l.AsRandom())
Console.WriteLine(i);
Console.ReadLine();
}
}
public static class MyExtensions
{
public static IEnumerable<T> AsRandom<T>(this IList<T> list)
{
int[] indexes = Enumerable.Range(0, list.Count).ToArray();
Random generator = new Random();
for (int i = 0; i < list.Count; ++i )
{
int position = generator.Next(i, list.Count);
yield return list[indexes[position]];
indexes[position] = indexes[i];
}
}
}
This uses a reverse Fisher-Yates shuffle on the indexes of the list we want to randomly enumerate through. Its a bit of a size hog (allocating 4*list.Count bytes), but runs in O(n).