Прежде всего, я знаю о перетасовке Фишера-Йейтса. Но позвольте сказать, ради аргументов, что я хочу разрешить пользователю выбирать опцию сортировки из раскрывающегося списка. Этот список будет включать "Случайный" вариант. Основываясь на результатах их выбора, я просто хочу заменить экземпляр IComparer для своего рода. Как выглядит IComparer?
Google раскрывает множество ошибочных результатов, которые все принимают эту форму:
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);
}
}
Тем не менее, эта реализация является предвзятой и даже может вызвать исключение в некоторых случаях. Предвзятость может быть продемонстрирована с помощью следующего кода:
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;
}
Итак, как вы могли реализовать случайный IComparer<T>
, который решил эти проблемы? Разрешено требовать, чтобы каждый вызов .Sort()
использовал отдельный экземпляр IComparer, поскольку я не вижу другого способа сделать это: элементы должны сравниваться с использованием какого-либо другого, действительно случайного значения, но это значение также должно быть согласованным для элемента в заданной операции сортировки.
У меня есть старт here, но он был отправлен в спешке, очень медленный и даже не возвращает все возможные виды (тестирование показывает, что это по крайней мере, устраняет смещение, если вы не считаете недостающие параметры). Я не ожидаю O (n) производительности, как Fisher-Yates, но я хочу что-то разумное (n log n для маленького n-го n), и я ожидаю, что он покажет все возможные виды. К сожалению, эта ссылка является текущим принятым ответом на этот вопрос, и поэтому я надеюсь, что смогу заменить ее чем-то немного лучше.
Если ничего другого, я хочу, чтобы это было магнитом для всех тех запросов Google, которые ищут решение IComparable, - что они попадут сюда вместо того, чтобы где-то еще сообщать им использовать неправильную версию.