wake-up-neo.com

Optimale LINQ-Abfrage, um eine zufällige Untersammlung zu erhalten - Shuffle

Bitte schlagen Sie einen einfachen Weg vor, um eine zufällig gemischte Sammlung von count 'n' aus einer Sammlung mit 'N' Elementen zu erhalten. wobei n <= N ist

42
Jobi Joy

Eine weitere Option ist, OrderBy zu verwenden und nach einem GUID -Wert zu sortieren, den Sie dazu verwenden können:

var result = sequence.OrderBy(elem => Guid.NewGuid());

Ich habe einige empirische Tests durchgeführt, um mich davon zu überzeugen, dass das oben Genannte tatsächlich eine zufällige Verteilung erzeugt (was es zu tun scheint). Sie können meine Ergebnisse unter Techniken für das zufällige Umordnen eines Arrays sehen.

33
Scott Mitchell

Neben der Antwort von mquander und Dan Blanchards Kommentar ist hier eine LINQ-freundliche Erweiterungsmethode, die eine Fisher-Yates-Durstenfeld-Shuffle durchführt:

// take n random items from yourCollection
var randomItems = yourCollection.Shuffle().Take(n);

// ...

public static class EnumerableExtensions
{
    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
    {
        return source.Shuffle(new Random());
    }

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (rng == null) throw new ArgumentNullException("rng");

        return source.ShuffleIterator(rng);
    }

    private static IEnumerable<T> ShuffleIterator<T>(
        this IEnumerable<T> source, Random rng)
    {
        var buffer = source.ToList();
        for (int i = 0; i < buffer.Count; i++)
        {
            int j = rng.Next(i, buffer.Count);
            yield return buffer[j];

            buffer[j] = buffer[i];
        }
    }
}
99
LukeH

Dies hat einige Probleme mit "Random-Bias" und ich bin sicher, dass es nicht optimal ist.

var r = new Random();
l.OrderBy(x => r.NextDouble()).Take(n);
11
user166390

Shuffle die Sammlung in zufälliger Reihenfolge und die ersten n-Elemente aus dem Ergebnis entnehmen.

6
mquander

Etwas weniger zufällig, aber effizient:

var rnd = new Random();
var toSkip = list.Count()-n;

if (toSkip > 0)
    toSkip = rnd.Next(toSkip);
else
    toSkip=0;

var randomlySelectedSequence = list.Skip(toSkip).Take(n);
0
Majid