Zunächst weiß ich über die Fisher-Yates Shuffle. Aber lassen Sie uns Argumente sagen, dass ich dem Benutzer erlauben möchte, eine Sortieroption aus einer Dropdown-Liste auszuwählen. Diese Liste würde eine "zufällige" Option enthalten. Basierend auf dem Ergebnis ihrer Auswahl möchte ich nur eine IComparer-Instanz für meine Sorte einsetzen. Wie würde der IComparer aussehen?Mischen mit IComparer
Google bringt eine Fülle von fehlerhaften Ergebnissen, das all diese Form annehmen:
public class NaiveRandomizer<T> : IComparer<T>
{
private static Random rand = new Random();
public int Compare(T x, T y)
{
return (x.Equals(y))?0:rand.Next(-1, 2);
}
}
jedoch, dass die Umsetzung vorgespannt ist, und wird sogar eine Ausnahme unter bestimmten Umständen werfen. Die Vorspannung kann mit dem folgenden Code demonstriert werden:
void Test()
{
Console.WriteLine("NaiveRandomizer Test:");
var data = new List<int>() {1,2,3};
var sortCounts = new Dictionary<string, int>(6);
var randomly = new NaiveRandomizer<int>();
for (int i=0;i<10000;i++)
{ //always start with same list, in _the same order_.
var dataCopy = new List<int>(data);
dataCopy.Sort(randomly);
var key = WriteList(dataCopy);
if (sortCounts.ContainsKey(key))
sortCounts[key]++;
else
sortCounts.Add(key, 1);
}
foreach (KeyValuePair<string, int> item in sortCounts)
Console.WriteLine(item.Key + "\t" + item.Value);
}
string WriteList<T>(List<T> list)
{
string delim = "";
string result = "";
foreach(T item in list)
{
result += delim + item.ToString();
delim = ", ";
}
return result;
}
So wie könnte man ein zufälliges IComparer<T>
implementieren, die diese Probleme gelöst? Es ist zulässig, dass jeder Aufruf an .Sort()
eine separate IComparer-Instanz verwendet, da ich keine andere Möglichkeit sehe: Elemente müssen mit einem anderen, wirklich zufälligen Wert verglichen werden, aber dieser Wert muss auch sein für einen Artikel innerhalb einer Sortieroperation konsistent sein.
Ich habe einen Start here, aber es war in Eile geschrieben, ist extrem langsam, und kehrt nicht sogar alle möglichen Sorten (Tests zeigen, dass es am wenigsten entbindet bei bias, wenn Sie die nicht zählen fehlende Optionen). Ich erwarte keine O (n) Leistung wie Fisher-Yates, aber ich möchte etwas Vernünftiges (n log n für ein kleines i n), und ich erwarte, dass es alle möglichen Arten zeigt. Leider ist dieser Link die aktuell akzeptierte Antwort für seine Frage und ich hoffe, dass ich ihn durch etwas Besseres ersetzen kann.
Wenn nichts anderes, möchte ich, dass dies ein Magnet für all diese Google-Abfragen auf der Suche nach einer IComparable-Lösung ist - dass sie hier landen anstatt irgendwo anders zu sagen ihnen die falsche Version zu verwenden.
Können Sie erklären, warum diese Implementierung voreingenommen ist oder eine Ausnahme auslöst? (für meine eigene Erbauung) –
Von was ich sehe, ist die Ausnahme NullReferenceException. Die Voreingenommenheit ... weiß es nicht. –
Ich werde etwas Code hinzufügen, um die Verzerrung zu demonstrieren. –