C# сортировка и сравнение по порядку
Я могу сортировать список с помощью сортировки или OrderBy. Какой из них быстрее? Оба работают над одним и тем же
алгоритм?
List<Person> persons = new List<Person>();
persons.Add(new Person("P005", "Janson"));
persons.Add(new Person("P002", "Aravind"));
persons.Add(new Person("P007", "Kazhal"));
1.
persons.Sort((p1,p2)=>string.Compare(p1.Name,p2.Name,true));
2.
var query = persons.OrderBy(n => n.Name, new NameComparer());
class NameComparer : IComparer<string>
{
public int Compare(string x,string y)
{
return string.Compare(x, y, true);
}
}
7 ответов:
почему бы не измерить:
class Program { class NameComparer : IComparer<string> { public int Compare(string x, string y) { return string.Compare(x, y, true); } } class Person { public Person(string id, string name) { Id = id; Name = name; } public string Id { get; set; } public string Name { get; set; } } static void Main() { List<Person> persons = new List<Person>(); persons.Add(new Person("P005", "Janson")); persons.Add(new Person("P002", "Aravind")); persons.Add(new Person("P007", "Kazhal")); Sort(persons); OrderBy(persons); const int COUNT = 1000000; Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < COUNT; i++) { Sort(persons); } watch.Stop(); Console.WriteLine("Sort: {0}ms", watch.ElapsedMilliseconds); watch = Stopwatch.StartNew(); for (int i = 0; i < COUNT; i++) { OrderBy(persons); } watch.Stop(); Console.WriteLine("OrderBy: {0}ms", watch.ElapsedMilliseconds); } static void Sort(List<Person> list) { list.Sort((p1, p2) => string.Compare(p1.Name, p2.Name, true)); } static void OrderBy(List<Person> list) { var result = list.OrderBy(n => n.Name, new NameComparer()).ToArray(); } }на моем компьютере при компиляции в режиме релиза эта программа печатает:
Sort: 1162ms OrderBy: 1269ms
обновление:
как предложил @Stefan вот результаты сортировки большого списка меньше раз:
List<Person> persons = new List<Person>(); for (int i = 0; i < 100000; i++) { persons.Add(new Person("P" + i.ToString(), "Janson" + i.ToString())); } Sort(persons); OrderBy(persons); const int COUNT = 30; Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < COUNT; i++) { Sort(persons); } watch.Stop(); Console.WriteLine("Sort: {0}ms", watch.ElapsedMilliseconds); watch = Stopwatch.StartNew(); for (int i = 0; i < COUNT; i++) { OrderBy(persons); } watch.Stop(); Console.WriteLine("OrderBy: {0}ms", watch.ElapsedMilliseconds);принты:
Sort: 8965ms OrderBy: 8460msв этом сценарии похоже, что OrderBy работает лучше.
обновление 2:
и с помощью случайных имена:
List<Person> persons = new List<Person>(); for (int i = 0; i < 100000; i++) { persons.Add(new Person("P" + i.ToString(), RandomString(5, true))); }где:
private static Random randomSeed = new Random(); public static string RandomString(int size, bool lowerCase) { var sb = new StringBuilder(size); int start = (lowerCase) ? 97 : 65; for (int i = 0; i < size; i++) { sb.Append((char)(26 * randomSeed.NextDouble() + start)); } return sb.ToString(); }выходы:
Sort: 8968ms OrderBy: 8728msтем не менее OrderBy быстрее
нет, это не один и тот же алгоритм. Для начала, LINQ
OrderByописана как стабильный (т. е. если два элемента имеют одинаковуюName, они появятся в исходном порядке).это также зависит от того, какой буфер запроса против его итерации несколько раз (по LINQ-к-объектов, если вы буферов результате, будет повторно заказать за
foreach).на
OrderByзапрос, я бы также хотел использовать:OrderBy(n => n.Name, StringComparer.{yourchoice}IgnoreCase);(для
{yourchoice}один изCurrentCulture,OrdinalилиInvariantCulture).этот метод использует массив.Сорт, который использует алгоритм быстрой сортировки. Этот реализации осуществляется нестрогая рода; то есть, если два элемента равны, их порядок может не быть консервированный. Напротив, стабильная сортировка сохраняет порядок элементов, которые они равны.
этот метод выполняет стабильная сортировка, то есть, если ключи от двух элементов равны, порядок элементов сохраняется. Напротив, нестабильная сортировка не сохраняет порядок элементов, имеющих один и тот же ключ. рода; то есть, если два элемента равны, их порядок может не быть консервированный. Напротив, стабильная сортировка сохраняет порядок элементов, которые они равны.
ответ Дарина Димитрова показывает, что
OrderByнемного быстрее, чемList.Sortпри столкновении с уже отсортированным входом. Я изменил его код, так что он неоднократно сортирует несортированные данные, иOrderByв большинстве случаев немного медленнее.кроме того,
OrderByтест используетToArrayдля принудительного перечисления перечислителя Linq, но это, очевидно, возвращает тип (Person[]), которая отличается от типа ввода (List<Person>). Поэтому я повторно запустил тест с помощьюToListа неToArrayи получил еще большую разницу:Sort: 25175ms OrderBy: 30259ms OrderByWithToList: 31458msкод:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; class Program { class NameComparer : IComparer<string> { public int Compare(string x, string y) { return string.Compare(x, y, true); } } class Person { public Person(string id, string name) { Id = id; Name = name; } public string Id { get; set; } public string Name { get; set; } public override string ToString() { return Id + ": " + Name; } } private static Random randomSeed = new Random(); public static string RandomString(int size, bool lowerCase) { var sb = new StringBuilder(size); int start = (lowerCase) ? 97 : 65; for (int i = 0; i < size; i++) { sb.Append((char)(26 * randomSeed.NextDouble() + start)); } return sb.ToString(); } private class PersonList : List<Person> { public PersonList(IEnumerable<Person> persons) : base(persons) { } public PersonList() { } public override string ToString() { var names = Math.Min(Count, 5); var builder = new StringBuilder(); for (var i = 0; i < names; i++) builder.Append(this[i]).Append(", "); return builder.ToString(); } } static void Main() { var persons = new PersonList(); for (int i = 0; i < 100000; i++) { persons.Add(new Person("P" + i.ToString(), RandomString(5, true))); } var unsortedPersons = new PersonList(persons); const int COUNT = 30; Stopwatch watch = new Stopwatch(); for (int i = 0; i < COUNT; i++) { watch.Start(); Sort(persons); watch.Stop(); persons.Clear(); persons.AddRange(unsortedPersons); } Console.WriteLine("Sort: {0}ms", watch.ElapsedMilliseconds); watch = new Stopwatch(); for (int i = 0; i < COUNT; i++) { watch.Start(); OrderBy(persons); watch.Stop(); persons.Clear(); persons.AddRange(unsortedPersons); } Console.WriteLine("OrderBy: {0}ms", watch.ElapsedMilliseconds); watch = new Stopwatch(); for (int i = 0; i < COUNT; i++) { watch.Start(); OrderByWithToList(persons); watch.Stop(); persons.Clear(); persons.AddRange(unsortedPersons); } Console.WriteLine("OrderByWithToList: {0}ms", watch.ElapsedMilliseconds); } static void Sort(List<Person> list) { list.Sort((p1, p2) => string.Compare(p1.Name, p2.Name, true)); } static void OrderBy(List<Person> list) { var result = list.OrderBy(n => n.Name, new NameComparer()).ToArray(); } static void OrderByWithToList(List<Person> list) { var result = list.OrderBy(n => n.Name, new NameComparer()).ToList(); } }
Я думаю, это важно отметить еще одно различие между
SortиOrderBy:предположим, что существует
Person.CalculateSalary()метод, который занимает много времени; возможно, даже больше, чем операция сортировки большого списка.сравнить
// Option 1 persons.Sort((p1, p2) => Compare(p1.CalculateSalary(), p2.CalculateSalary())); // Option 2 var query = persons.OrderBy(p => p.CalculateSalary());2 может иметь превосходную производительность, потому что он вызывает только
CalculateSalaryметод n раз, в то время как можно назватьCalculateSalaryдо 2n log (n) раз, в зависимости от успеха алгоритма сортировки.
вы должны рассчитать сложность алгоритмов, используемых методами OrderBy и Sort. QuickSort имеет сложность n (log n), как я помню, где n-длина массива.
Я тоже искал заказатьпо, но я не смог найти никакой информации даже в библиотеке MSDN. если у вас нет одинаковых значений и сортировки, связанных только с одним свойством, я предпочитаю использовать Метод Sort (); если нет, то используйте OrderBy.
Я просто хочу добавить, что orderby является более полезным.
почему?
потому что я могу сделать это
Dim thisAccountBalances = account.DictOfBalances.Values.ToList thisAccountBalances.ForEach(Sub(x) x.computeBalanceOtherFactors()) thisAccountBalances=thisAccountBalances.OrderBy(Function(x) x.TotalBalance).tolist listOfBalances.AddRange(thisAccountBalances)почему сложные сравнения? Просто сортировка на основе поля. Здесь я сортирую на основе TotalBalance.
очень просто
Я не могу с сортировки. Интересно, почему. Хорошо с заказатьпо.
что касается скорости. Это всегда O (n)
в двух словах :
Сортировка Списка / Массива ():
- нестрогая сортировка.
- сделать на месте.
- Используйте Introsort / Quicksort.
- Пользовательское сравнение выполняется путем предоставления компаратора. Если сравнение дорого, оно может быть медленнее, чем OrderBy() (которые позволяют использовать ключи, см. ниже).
OrderBy/ThenBy ():
- стабильная сортировка.
- не на месте.
- Использование Быстрой Сортировки. Быстрая сортировка не является стабильной сортировки. Вот трюк: при сортировке, если два элемента имеют одинаковый ключ, он сравнивает их начальный порядок (который был сохранен до сортировки).
- позволяет использовать ключи (используя лямбды) для сортировки элементов по их значениям (например:
x => x.Id). Все ключи извлекаются сначала перед сортировкой. Это может привести к повышению производительности по сравнению с использованием Sort() и пользовательского компаратора.источники: MDSN,источник и dotnet / coreclr репозиторий (GitHub).
некоторые из перечисленных выше операторов основаны на текущей реализации .NET framework (4.7.2). Это может измениться в будущем.
Comments