Sortまたは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);
}
}
なぜ測定しないのですか:
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
はstableとして文書化されています(つまり、2つのアイテムのName
が同じ場合、それらは ' llは元の順序で表示されます)。
また、クエリをバッファリングするか、数回反復するかによっても異なります(結果をバッファリングしない限り、foreach
ごとにLINQ-to-Objectsが並べ替えられます)。
OrderBy
クエリの場合、次のものも使用したいと思います。
OrderBy(n => n.Name, StringComparer.{yourchoice}IgnoreCase);
(ために {yourchoice}
CurrentCulture
、Ordinal
、またはInvariantCulture
のいずれか)。
このメソッドは、QuickSortアルゴリズムを使用するArray.Sortを使用します。この実装は、不安定なソートを実行します。つまり、2つの要素が等しい場合、それらの順序は保持されない可能性があります。対照的に、安定したソートでは、等しい要素の順序が保持されます。
このメソッドは安定したソートを実行します。つまり、2つの要素のキーが等しい場合、要素の順序は保持されます。対照的に、不安定なソートでは、同じキーを持つ要素の順序は保持されません。ソート;つまり、2つの要素が等しい場合、それらの順序は保持されない可能性があります。対照的に、安定したソートでは、等しい要素の順序が保持されます。
Darin Dimitrovの答えは、すでにソートされた入力に直面したとき、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回、Sort
オプションはCalculateSalary
を呼び出す場合があります 2 n log(n) 回まで、ソートアルゴリズムの成功に応じて.
手短に :
リスト/配列ソート():
OrderBy/ThenBy():
x => x.Id
)。ソートする前に、すべてのキーが最初に抽出されます。これにより、Sort()およびカスタム比較演算子を使用するよりもパフォーマンスが向上する場合があります。ソース: [〜#〜] mdsn [〜#〜] 、 参照ソース および dotnet/coreclr リポジトリ(GitHub)。
上記のステートメントの一部は、現在の.NETフレームワークの実装(4.7.2)に基づいています。将来変更される可能性があります。
メソッドOrderByおよびSortで使用されるアルゴリズムの複雑さを計算する必要があります。私が覚えているように、QuickSortにはn(log n)の複雑さがあります。ここで、nは配列の長さです。
私もorderbyを検索しましたが、msdnライブラリでも情報を見つけることができませんでした。 1つのプロパティのみに関連する同じ値と並べ替えがない場合、Sort()メソッドを使用することを好みます。そうでない場合は、OrderByを使用します。