Mische alle (I)List
mit einer Erweiterungsmethode, die auf dem Fisher-Yates-Shuffle basiert :
private static Random rng = new Random();
public static void Shuffle<T>(this IList<T> list)
{
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;
}
}
Verwendungszweck:
List<Product> products = GetProducts();
products.Shuffle();
Der obige Code verwendet die viel kritisierte System.Random-Methode, um Swap-Kandidaten auszuwählen. Es ist schnell, aber nicht so zufällig, wie es sein sollte. Wenn Sie eine bessere Qualität der Zufälligkeit in Ihren Mischvorgängen benötigen, verwenden Sie den Zufallszahlengenerator in System.Security.Cryptography wie folgt:
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;
}
}
Ein einfacher Vergleich ist in diesem Blog (WayBack Machine) verfügbar .
Bearbeiten: Seit ich diese Antwort vor ein paar Jahren geschrieben habe, haben viele Leute mich kommentiert oder geschrieben, um auf den großen dummen Fehler in meinem Vergleich hinzuweisen. Sie haben natürlich recht. Es ist nichts falsch mit System.Random, wenn es so verwendet wird, wie es beabsichtigt war. In meinem ersten Beispiel oben instanziiere ich die Variable rng innerhalb der Shuffle-Methode, die nach Problemen fragt, wenn die Methode wiederholt aufgerufen werden soll. Unten finden Sie ein festes, vollständiges Beispiel, das auf einem wirklich nützlichen Kommentar basiert, den @weston heute hier auf SO erhalten hat.
Program.cs:
using System;
using System.Collections.Generic;
using System.Threading;
namespace SimpleLottery
{
class Program
{
private static void Main(string[] args)
{
var numbers = new List<int>(Enumerable.Range(1, 75));
numbers.Shuffle();
Console.WriteLine("The winning numbers are: {0}", string.Join(", ", numbers.GetRange(0, 5)));
}
}
public static class ThreadSafeRandom
{
[ThreadStatic] private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
}
}
static class MyExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}