2011-12-20T04:55:52の更新内容

programming/netfx/sorting/index.wiki.txt

current previous
1,2672 0,0
+
${smdncms:title,ソート}
+
${smdncms:header_title,ソート (並べ替え)}
+
${smdncms:keywords,ソート,並べ替え,昇順,降順,配列,コレクション,List,Dictionary,Sort,OrderBy,ThenBy,Comparison}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
ここでは配列・List・Dictionary等のコレクションのソートについて解説します。 なお、.NET Frameworkに標準で用意されているソート処理についてのみを扱います。
+

          
+
-関連するページ
+
--[[programming/netfx/comparison]]
+
---[[programming/netfx/comparison/0_comparison]]
+
--[[programming/netfx/collections]]
+
---[[programming/netfx/collections/0_abstract]]
+
---[[programming/netfx/collections/2_generic]]
+
--[[programming/netfx/string]]
+
---[[programming/netfx/string/2_2_compareoptions]]
+

          
+
#googleadunit(banner)
+

          
+
*ソート [#SortAscending]
+
ここでは配列・List等の各種コレクションのソート方法について見ていきます。 なお、まずは昇順(小さい順)でのソートについて見ていきます。 [[降順(大きい順)でのソート方法>#SortDescending]]については追って解説します。 また、数値・文字列等の単純型(基本型)を格納する配列・コレクションのソートについてのみ説明します。 複合型を格納している配列・コレクションのソートについては[[複合型のソート>#SortCompositeType]]で追って解説します。
+

          
+
**配列のソート (Array.Sort) [#Array.Sort]
+
配列をソートするには、&msdn(netfx,member,System.Array.Sort){Array.Sortメソッド};を使います。 このメソッドは静的メソッドです。 ソートされた配列が作成され戻り値として返されるのではなく、引数に指定された配列自体をソートします。
+

          
+
#tabpage(C#)
+
#code(cs,数値のソート){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象の配列
+
    int[] arr = new int[] {5, 2, 3, 1, 4};
+

          
+
    // ソート
+
    Array.Sort(arr);
+

          
+
    foreach (int val in arr) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#code(cs,文字列のソート){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象の配列
+
    string[] arr = new string[] {"ab", "abc", "aa", "a", "b", "acb"};
+

          
+
    // ソート
+
    Array.Sort(arr);
+

          
+
    foreach (string val in arr) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,数値のソート){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象の配列
+
    Dim arr() As Integer = New Integer() {5, 2, 3, 1, 4}
+

          
+
    ' ソート
+
    Array.Sort(arr)
+

          
+
    For Each val As Integer In arr
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#code(vb,文字列のソート){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象の配列
+
    Dim arr() As String = New String() {"ab", "abc", "aa", "a", "b", "acb"}
+

          
+
    ' ソート
+
    Array.Sort(arr)
+

          
+
    For Each val As String In arr
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果 (数値のソート)){{
+
1, 2, 3, 4, 5, 
+
}}
+

          
+
#prompt(実行結果 (文字列のソート)){{
+
a, aa, ab, abc, acb, b, 
+
}}
+

          
+
**Listのソート (List.Sort) [#List.Sort]
+
List<T>をソートするには、&msdn(netfx,member,System.Collections.Generic.List`1.Sort){List.Sortメソッド};を使います。 Array.Sortメソッドとは異なりこのメソッドはインスタンスメソッドですが、動作はArray.Sortメソッドと同様にSortメソッドを呼び出したインスタンス自体がソートされます。 戻り値は無いため、ソートされたList<T>が作成されて戻り値として返されることはありません。
+

          
+
#tabpage(C#)
+
#code(cs,数値のソート){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のList<int>
+
    List<int> list = new List<int>(new int[] {5, 2, 3, 1, 4});
+

          
+
    // ソート
+
    list.Sort();
+

          
+
    foreach (int val in list) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#code(cs,文字列のソート){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のList<string>
+
    List<string> list = new List<string>(new string[] {"ab", "abc", "aa", "a", "b", "acb"});
+

          
+
    // ソート
+
    list.Sort();
+

          
+
    foreach (string val in list) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,数値のソート){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のList(Of Integer)
+
    Dim list As New List(Of Integer)(New Integer() {5, 2, 3, 1, 4})
+

          
+
    ' ソート
+
    list.Sort()
+

          
+
    For Each val As Integer In list
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#code(vb,文字列のソート){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のList(Of String)
+
    Dim list As New List(Of String)(New String() {"ab", "abc", "aa", "a", "b", "acb"})
+

          
+
    ' ソート
+
    list.Sort()
+

          
+
    For Each val As String In list
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果 (数値のソート)){{
+
1, 2, 3, 4, 5, 
+
}}
+

          
+
#prompt(実行結果 (文字列のソート)){{
+
a, aa, ab, abc, acb, b, 
+
}}
+

          
+
**ArrayListのソート (ArrayList.Sort) [#ArrayList.Sort]
+
ArrayListをソートするには、&msdn(netfx,member,System.Collections.ArrayList.Sort){ArrayList.Sortメソッド};を使います。 使い方・動作と結果はList<T>.Sortと同様です。
+

          
+
#tabpage(C#)
+
#code(cs,数値のソート){{
+
using System;
+
using System.Collections;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のArrayList
+
    ArrayList list = new ArrayList(new int[] {5, 2, 3, 1, 4});
+

          
+
    // ソート
+
    list.Sort();
+

          
+
    foreach (int val in list) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#code(cs,文字列のソート){{
+
using System;
+
using System.Collections;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のArrayList
+
    ArrayList list = new ArrayList(new string[] {"ab", "abc", "aa", "a", "b", "acb"});
+

          
+
    // ソート
+
    list.Sort();
+

          
+
    foreach (string val in list) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,数値のソート){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のArrayList
+
    Dim list As New ArrayList(New Integer() {5, 2, 3, 1, 4})
+

          
+
    ' ソート
+
    list.Sort()
+

          
+
    For Each val As Integer In list
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#code(vb,文字列のソート){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のArrayList
+
    Dim list As New ArrayList(New String() {"ab", "abc", "aa", "a", "b", "acb"})
+

          
+
    ' ソート
+
    list.Sort()
+

          
+
    For Each val As String In list
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果 (数値のソート)){{
+
1, 2, 3, 4, 5, 
+
}}
+

          
+
#prompt(実行結果 (文字列のソート)){{
+
a, aa, ab, abc, acb, b, 
+
}}
+

          
+
**SortedList, SortedDictionaryのソート [#SortedListSortedDictionary]
+
&msdn(netfx,type,System.Collections.Generic.SortedList`2){SortedList<TKey, TValue>};および&msdn(netfx,type,System.Collections.Generic.SortedDictionary`2){SortedDictionary<TKey, TValue>};では、要素を格納した時点で''自動的にソートされる''ため、明示的にソートを行うメソッドはありません。 SortedList<TKey, TValue>およびSortedDictionary<TKey, TValue>では、キー(TKey)の値を基準にソートされます。
+

          
+
以下の例ではSortedListを使用していますが、SortedDictionaryでも結果は同様です。
+

          
+
#tabpage(C#)
+
#code(cs,数値をキーとしたソート){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のSortedList<int, string>
+
    SortedList<int, string> list = new SortedList<int, string>();
+

          
+
    list.Add(2, "Alice");
+
    list.Add(3, "Bob");
+
    list.Add(5, "Charlie");
+
    list.Add(1, "Dave");
+
    list.Add(4, "Eve");
+

          
+
    foreach (KeyValuePair<int, string> pair in list) {
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#code(cs,文字列をキーとしたソート){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のList<string>
+
    SortedList<string, int> list = new SortedList<string, int>();
+

          
+
    list.Add("Dave", 1);
+
    list.Add("Alice", 2);
+
    list.Add("Bob", 3);
+
    list.Add("Eve", 4);
+
    list.Add("Charlie", 5);
+

          
+
    foreach (KeyValuePair<string, int> pair in list) {
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,数値をキーとしたソート){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のSortedList(Of Integer, String)
+
    Dim list As New SortedList(Of Integer, String)
+

          
+
    list.Add(2, "Alice")
+
    list.Add(3, "Bob")
+
    list.Add(5, "Charlie")
+
    list.Add(1, "Dave")
+
    list.Add(4, "Eve")
+

          
+
    For Each pair As KeyValuePair(Of Integer, String) In list
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#code(vb,文字列をキーとしたソート){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のSortedList(Of String, Integer)
+
    Dim list As New SortedList(Of String, Integer)
+

          
+
    list.Add("Dave", 1)
+
    list.Add("Alice", 2)
+
    list.Add("Bob", 3)
+
    list.Add("Eve", 4)
+
    list.Add("Charlie", 5)
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In list
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果 (数値をキーとしたソート)){{
+
1 Dave
+
2 Alice
+
3 Bob
+
4 Eve
+
5 Charlie
+
}}
+

          
+
#prompt(実行結果 (文字列をキーとしたソート)){{
+
Alice 2
+
Bob 3
+
Charlie 5
+
Dave 1
+
Eve 4
+
}}
+

          
+
SortedList<TKey, TValue>およびSortedDictionary<TKey, TValue>で、値(TValue)の値を基準にソートする手段は用意されていないため、独自にソート処理を実装する必要があります。 詳しくは[[Dictionaryのソート>#SortDictionary]]の解説を参照してください。
+

          
+
**Dictionaryのソート [#SortDictionary]
+
&msdn(netfx,type,System.Collections.Generic.Dictionary`2){Dictionary<TKey, TValue>};にはソートを行うメソッドや、SortedListとSortedDictionaryのように自動的にソートする機能はありません。 常にソートされた状態にしておきたい場合はSortedList・SortedDictionaryを選ぶことも出来ますが、要素の追加の度にソートされることによる処理速度の低下を無視できないなどの理由がある場合は、やはりDictionaryを使い、必要な時にソートを行うという方法が必要になります。
+

          
+
ここでは、Dictionaryをソートする方法についていくつかのやり方を見ていきます。 なお、Dictionary自体をソートすることは出来ないため、以下のやり方は、いずれも元のDictionaryの状態は変更せずにDictionaryの内容だけをソートされた状態で取得する方法となります。
+

          
+
***KeyValuePairのリストに変換してソートする
+
1つ目は、Dictionaryの内容を、&msdn(msdn,type,System.Collections.Generic.KeyValuePair`2){KeyValuePair};のリストに変えてからソートする方法です。
+

          
+
#column
+
|>|Dictionary<string, int>|h
+
|"Bob"|3|
+
|"Dave"|1|
+
|"Alice"|2|
+
|"Charlie"|5|
+
|"Eve"|4|
+
#column
+
→ 変換 →
+
#column
+
|>|List<KeyValuePair<string, int>>|h
+
|{"Bob", 3}|
+
|{"Dave", 1}|
+
|{"Alice", 2}|
+
|{"Charlie", 5}|
+
|{"Eve", 4}|
+
#column
+
→ ソート →
+
#column
+
|>|List<KeyValuePair<string, int>>|h
+
|{"Alice", 2}|
+
|{"Bob", 3}|
+
|{"Charlie", 5}|
+
|{"Dave", 1}|
+
|{"Eve", 4}|
+
#column-end
+

          
+
KeyValuePairはDictionaryの内部で使われている構造体で、キーと値のペアを一つの構造体として格納するためのものです。 Dictionaryを直接列挙する場合などにも使われます。 DictionaryをこのKeyValuePairのリストに変換してから、&msdn(netfx,member,System.Collections.Generic.List`1.Sort){List.Sortメソッド};を使ってソートします。 ただし、KeyValuePairはそのままではソートできず、List.SortメソッドはInvalidOperationExceptionをスローします。 このため、KeyValuePairのソート方法(比較方法)を定義したメソッドを別途用意し、ソートする際にSortメソッドに渡す必要があります。 Sortメソッドと比較方法の定義(Comparision<T>デリゲート)については、[[複合型のソート>#SortCompositeType]]で改めて詳しく解説します。
+

          
+
#tabpage(C#)
+
#code(cs,List.Sortを使ったDictionaryのソート){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  // 二つのKeyValuePair<string, int>を比較するためのメソッド
+
  static int CompareKeyValuePair(KeyValuePair<string, int> x, KeyValuePair<string, int> y)
+
  {
+
    // Keyで比較した結果を返す
+
    return string.Compare(x.Key, y.Key);
+
  }
+

          
+
  static void Main()
+
  {
+
    // ソート対象のDictionary<string, int>
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

          
+
    dict.Add("Bob", 3);
+
    dict.Add("Dave", 1);
+
    dict.Add("Alice", 2);
+
    dict.Add("Charlie", 5);
+
    dict.Add("Eve", 4);
+

          
+
    // List<KeyValuePair<string, int>>を作成し、Dictionaryの内容をコピー
+
    List<KeyValuePair<string, int>> pairs = new List<KeyValuePair<string, int>>(dict);
+

          
+
    // List.Sortメソッドを使ってソート
+
    pairs.Sort(CompareKeyValuePair);
+

          
+
    foreach (KeyValuePair<string, int> pair in pairs) {
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,List.Sortを使ったDictionaryのソート){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  ' 二つのKeyValuePair(Of String, Integer)を比較するためのメソッド
+
  Shared Function CompareKeyValuePair(ByVal x As KeyValuePair(Of String, Integer), _
+
                                      ByVal y As KeyValuePair(Of String, Integer)) As Integer
+
    ' Keyで比較した結果を返す
+
    Return String.Compare(x.Key, y.Key)
+
  End Function
+

          
+
  Shared Sub Main()
+
    ' ソート対象のDictionary
+
    Dim dict As New Dictionary(Of String, Integer)()
+

          
+
    dict.Add("Bob", 3)
+
    dict.Add("Dave", 1)
+
    dict.Add("Alice", 2)
+
    dict.Add("Charlie", 5)
+
    dict.Add("Eve", 4)
+

          
+
    ' List(Of KeyValuePair(Of String, Integer))を作成し、Dictionaryの内容をコピー
+
    Dim pairs As New List(Of KeyValuePair(Of String, Integer))(dict)
+

          
+
    ' List.Sortメソッドを使ってソート
+
    pairs.Sort(AddressOf CompareKeyValuePair)
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In pairs
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Alice 2
+
Bob 3
+
Charlie 5
+
Dave 1
+
Eve 4
+
}}
+

          
+
なお、上記の例ではキーを比較したためDictionaryはキーを基準にソートされましたが、CompareKeyValuePairを次のようにすることで値でソートできるようになります。
+

          
+
#tabpage(C#)
+
#code(cs,Dictionaryを値でソートする例){{
+
// 二つのKeyValuePair<string, int>を比較するためのメソッド
+
static int CompareKeyValuePair(KeyValuePair<string, int> x, KeyValuePair<string, int> y)
+
{
+
  // Valueで比較した結果を返す
+
  return x.Value.CompareTo(y.Value);
+

          
+
  // 単に次のようにしても同じ
+
  // return x.Value - y.Value;
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,Dictionaryを値でソートする例){{
+
' 二つのKeyValuePair(Of String, Integer)を比較するためのメソッド
+
Shared Function CompareKeyValuePair(ByVal x As KeyValuePair(Of String, Integer), _
+
                                    ByVal y As KeyValuePair(Of String, Integer)) As Integer
+
  ' Valueで比較した結果を返す
+
  Return x.Value.CompareTo(b.Value)
+

          
+
  ' 単に次のようにしても同じ
+
  ' Return y.Value - b.Value
+
End Function
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Dave 1
+
Alice 2
+
Bob 3
+
Eve 4
+
Charlie 5
+
}}
+

          
+
***キーと値の配列に変換してソートする
+
2つ目は、Dictionaryの内容を、キーと値で個別の配列に変えてからソートする方法です。
+

          
+
#column
+
|>|Dictionary<string, int>|h
+
|"Dave"|1|
+
|"Alice"|2|
+
|"Bob"|3|
+
|"Eve"|4|
+
|"Charlie"|5|
+
#column
+
→ 変換 →
+
#column
+
|string[]|⇔|int[]|h
+
|"Dave"|⇔|1|
+
|"Alice"|⇔|2|
+
|"Bob"|⇔|3|
+
|"Eve"|⇔|4|
+
|"Charlie"|⇔|5|
+
#column
+
→ ソート →
+
#column
+
|string[]|⇔|int[]|h
+
|"Alice"|⇔|2|
+
|"Bob"|⇔|3|
+
|"Charlie"|⇔|5|
+
|"Dave"|⇔|1|
+
|"Eve"|⇔|4|
+
#column-end
+

          
+
&msdn(netfx,member,System.Array.Sort){Array.Sortメソッド};には、それぞれにキーと値が格納された二つの配列を渡すと、キーの配列に従って値の配列を並べ替えることができるオーバーロードが用意されています。 これを使うことでDictionaryのソートを行うことが出来ます。 KeyValuePairは使わないため、キーが単純型であればソート方法(比較方法)を定義する必要がありません。
+

          
+
#tabpage(C#)
+
#code(cs,Array.Sortを使ったDictionaryのソート){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のDictionary<string, int>
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

          
+
    dict.Add("Bob", 3);
+
    dict.Add("Dave", 1);
+
    dict.Add("Alice", 2);
+
    dict.Add("Charlie", 5);
+
    dict.Add("Eve", 4);
+

          
+
    // キーと値を格納する配列を作成し、Dictionaryの内容をコピー
+
    string[] sortedKeys = new string[dict.Count];
+
    int[] sortedValues = new int[dict.Count];
+

          
+
    dict.Keys.CopyTo(sortedKeys, 0);
+
    dict.Values.CopyTo(sortedValues, 0);
+

          
+
    // Array.Sort(Array, Array)メソッドを使ってソート
+
    Array.Sort(sortedKeys, sortedValues);
+

          
+
    for (int index = 0; index < sortedKeys.Length; index++) {
+
      Console.WriteLine("{0} {1}", sortedKeys[index], sortedValues[index]);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,Array.Sortを使ったDictionaryのソート){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のDictionary
+
    Dim dict As New Dictionary(Of String, Integer)()
+

          
+
    dict.Add("Bob", 3)
+
    dict.Add("Dave", 1)
+
    dict.Add("Alice", 2)
+
    dict.Add("Charlie", 5)
+
    dict.Add("Eve", 4)
+

          
+
    ' キーと値を格納する配列を作成し、Dictionaryの内容をコピー
+
    Dim sortedKeys(dict.Count - 1) As String
+
    Dim sortedValues(dict.Count - 1) As Integer
+

          
+
    dict.Keys.CopyTo(sortedKeys, 0)
+
    dict.Values.CopyTo(sortedValues, 0)
+

          
+
    ' Array.Sort(Array, Array)メソッドを使ってソート
+
    Array.Sort(sortedKeys, sortedValues)
+

          
+
    For index As Integer = 0 To sortedKeys.Length - 1
+
      Console.WriteLine("{0} {1}", sortedKeys(index), sortedValues(index))
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Alice 2
+
Bob 3
+
Charlie 5
+
Dave 1
+
Eve 4
+
}}
+

          
+
なお、Array.Sortに渡す配列はキーの配列・値の配列の順となっていますが、この順序と逆に指定することで値でソートできるようになります。
+

          
+
#tabpage(C#)
+
#code(cs,Dictionaryを値でソートする例){{
+
    :
+
    :
+
dict.Keys.CopyTo(sortedKeys, 0);
+
dict.Values.CopyTo(sortedValues, 0);
+

          
+
// Array.Sort(Array, Array)メソッドを使ってソート
+
Array.Sort(sortedValues, sortedKeys);
+
    :
+
    :
+
}}
+
#tabpage(VB)
+
#code(vb,Dictionaryを値でソートする例){{
+
    :
+
    :
+
dict.Keys.CopyTo(sortedKeys, 0)
+
dict.Values.CopyTo(sortedValues, 0)
+

          
+
' Array.Sort(Array, Array)メソッドを使ってソート
+
Array.Sort(sortedValues, sortedKeys)
+
    :
+
    :
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Dave 1
+
Alice 2
+
Bob 3
+
Eve 4
+
Charlie 5
+
}}
+

          
+
***OrderByを使ってソートする
+
拡張メソッドであるOrderByメソッドを使うことでもDictionaryをソートできます。 [[OrderByメソッドを使ったDictionaryのソート>#Dictionary.OrderBy]]については後述します。
+

          
+
**Enumerable.OrderBy [#Enumerable.OrderBy]
+
IEnumerable<T>を実装しているコレクションの場合、拡張メソッドである&msdn(netfx,member,System.Core.dll,System.Linq.Enumerable.OrderBy){OrderBy};を使うことでもソートする事ができます。
+

          
+
配列やList、Dictionaryを含め、&msdn(netfx,ns,System.Collections.Generic){System.Collections.Generic名前空間};にあるコレクションクラスはいずれもIEnumerable<T>を実装しているため、OrderByメソッドでソートする事ができます。
+

          
+
***OrderByメソッドの使い方と動作
+
OrderByメソッドを使って配列・Listをソートする例について見ていきます。
+

          
+
#tabpage(C#)
+
#code(cs,配列のソート){{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象の配列
+
    int[] arr = new int[] {5, 2, 3, 1, 4};
+

          
+
    // ソート
+
    IOrderedEnumerable<int> sorted = arr.OrderBy(val => val);
+

          
+
    foreach (int val in sorted) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+

          
+
#code(cs,Listのソート){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のList<int>
+
    List<int> list = new List<int>(new int[] {5, 2, 3, 1, 4});
+

          
+
    // ソート
+
    IOrderedEnumerable<int> sorted = list.OrderBy(val => val);
+

          
+
    foreach (int val in sorted) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,配列のソート){{
+
Imports System
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象の配列
+
    Dim arr() As Integer = New Integer() {5, 2, 3, 1, 4}
+

          
+
    ' ソート
+
    Dim sorted As IOrderedEnumerable(Of Integer) = arr.OrderBy(Function(val) val)
+

          
+
    For Each val As Integer In sorted
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+

          
+
#code(vb,Listのソート){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のList(Of Integer)
+
    Dim list As New List(Of Integer)(New Integer() {5, 2, 3, 1, 4})
+

          
+
    ' ソート
+
    Dim sorted As IOrderedEnumerable(Of Integer) = list.OrderBy(Function(val) val)
+

          
+
    For Each val As Integer In sorted
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
1, 2, 3, 4, 5, 
+
}}
+

          
+
Array.SortメソッドやList.Sortメソッドとは異なり、OrderByメソッドは元の配列・コレクションの状態は変更しません。 代わりにソート後の結果となる&msdn(netfx,type,System.Core.dll,System.Linq.IOrderedEnumerable`1){IOrderedEnumerable<TElement>};を返します。 なお、OrderByは''遅延実行''されるため、戻り値に対してforeach等で列挙操作を行うことで初めてソートが行われます。 IOrderedEnumerable<TElement>はIEnumerable<T>から派生したインターフェイスなので、遅延実行される点を除けば違いを特に意識しなくてもIEnumerable<T>と同様に扱えます。 IEnumerable<T>については[[programming/netfx/enumeration]]を参照してください。
+

          
+
OrderByメソッドの引数には、ソートの際に使用するキーを選択するメソッドへのデリゲート(またはラムダ式)を指定します。 先の例はラムダ式を用いたものですが、これをメソッドとして展開すると次のようになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static int KeySelector(int val)
+
  {
+
    // 要素の値そのものを並べ替えの際のキーとする
+
    return val;
+
  }
+

          
+
  static void Main()
+
  {
+
    // ソート対象の配列
+
    int[] arr = new int[] {5, 2, 3, 1, 4};
+

          
+
    // ソート
+
    IOrderedEnumerable<int> sorted = arr.OrderBy(KeySelector);
+

          
+
    foreach (int val in sorted) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Function KeySelector(ByVal val As Integer) As Integer
+
    ' 要素の値そのものを並べ替えの際のキーとする
+
    Return val
+
  End Function
+

          
+
  Shared Sub Main()
+
    ' ソート対象の配列
+
    Dim arr() As Integer = New Integer() {5, 2, 3, 1, 4}
+

          
+
    ' ソート
+
    Dim sorted As IOrderedEnumerable(Of Integer) = arr.OrderBy(AddressOf KeySelector)
+

          
+
    For Each val As Integer In sorted
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
OrderByメソッドの引数についてもう少し詳しく見ていきます。 OrderByメソッドではソートの際に何をキーとしてソートするかを指定する必要があります。 これは、単純型でも複合型でもソートできるようにするために必要となるものです。 単純型の配列・コレクションの場合は単に''要素そのものをキー''とすればよいため、上記の例のように一見するとあまり意味のない記述となるのですが、Dictionaryや複合型の配列・コレクションの場合は、何を基準にソートするかによってキーを定める必要があるため、この引数が意味を持つようになります。
+

          
+
***OrderByメソッドを使ったDictionaryのソート [#Dictionary.OrderBy]
+
具体的な例として、OrderByメソッドを使ってDictionaryのソートを行う例について見てみます。 次の例のメソッドKeySelectorはキーの選択を行うメソッドです。 Dictionaryの場合は個々の要素がKeyValuePairとして格納されているため、''KeyValuePairの何をキーとするか''を定める必要があります。 Dictionaryのキーでソートするためには、KeyValuePair.Keyプロパティを並べ替えの際のキーとするようにします。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Sample {
+
  static string KeySelector(KeyValuePair<string, int> pair)
+
  {
+
    // 並べ替えの際のキーにKeyの値を使用する
+
    return pair.Key;
+
  }
+

          
+
  static void Main()
+
  {
+
    // ソート対象のDictionary<string, int>
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

          
+
    dict.Add("Bob", 3);
+
    dict.Add("Dave", 1);
+
    dict.Add("Alice", 2);
+
    dict.Add("Charlie", 5);
+
    dict.Add("Eve", 4);
+

          
+
    // ソート
+
    IOrderedEnumerable<KeyValuePair<string, int>> sorted = dict.OrderBy(KeySelector);
+

          
+
    foreach (KeyValuePair<string, int> pair in sorted) {
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Function KeySelector(ByVal pair As KeyValuePair(Of String, Integer)) As String
+
    ' 並べ替えの際のキーにKeyの値を使用する
+
    Return pair.Key
+
  End Function
+

          
+
  Shared Sub Main()
+
    ' ソート対象のDictionary
+
    Dim dict As New Dictionary(Of String, Integer)()
+

          
+
    dict.Add("Bob", 3)
+
    dict.Add("Dave", 1)
+
    dict.Add("Alice", 2)
+
    dict.Add("Charlie", 5)
+
    dict.Add("Eve", 4)
+

          
+
    ' ソート
+
    Dim sorted As IOrderedEnumerable(Of KeyValuePair(Of String, Integer)) = dict.OrderBy(AddressOf KeySelector)
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In sorted
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Alice 2
+
Bob 3
+
Charlie 5
+
Dave 1
+
Eve 4
+
}}
+

          
+
なお、比較のために上記の例をラムダ式を使ったものに書き換えると次のようになります。 キーを選択するコードをメソッドとして記述する必要がないため、よりシンプルに記述できます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のDictionary<string, int>
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

          
+
    dict.Add("Bob", 3);
+
    dict.Add("Dave", 1);
+
    dict.Add("Alice", 2);
+
    dict.Add("Charlie", 5);
+
    dict.Add("Eve", 4);
+

          
+
    // ソート
+
    IOrderedEnumerable<KeyValuePair<string, int>> sorted = dict.OrderBy(pair => pair.Key);
+

          
+
    foreach (KeyValuePair<string, int> pair in sorted) {
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のDictionary
+
    Dim dict As New Dictionary(Of String, Integer)()
+

          
+
    dict.Add("Bob", 3)
+
    dict.Add("Dave", 1)
+
    dict.Add("Alice", 2)
+
    dict.Add("Charlie", 5)
+
    dict.Add("Eve", 4)
+

          
+
    ' ソート
+
    Dim sorted As IOrderedEnumerable(Of KeyValuePair(Of String, Integer)) = _
+
      dict.OrderBy(Function(pair) pair.Key)
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In sorted
+
      Console.WriteLine("{0} {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
ここまで例ではKeyValuePair.Keyをキーとしましたが、Dictionaryを値でソートしたい場合は、次のようにKeyValuePair.ValueをキーとするようにKeySelectorを変えるだけで出来ます(キーの型に合わせてメソッドの戻り値を変えている点に注意してください)。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
static int KeySelector(KeyValuePair<string, int> pair)
+
{
+
  // 並べ替えの際のキーにValueの値を使用する
+
  return pair.Value;
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Shared Function KeySelector(ByVal pair As KeyValuePair(Of String, Integer)) As Integer
+
  ' 並べ替えの際のキーにValueの値を使用する
+
  Return pair.Value
+
End Function
+
}}
+
#tabpage-end
+

          
+
ラムダ式の場合はメソッドを使って記述する場合より簡単で、次のようにします。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
dict.OrderBy(pair => pair.Value);
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
dict.OrderBy(Function(pair) pair.Value)
+
}}
+
#tabpage-end
+

          
+
なお、OrderByメソッドの代わりに[[OrderByDescendingメソッド>#Enumerable.OrderByDescending]]を使うと、昇順ではなく降順でソートすることができます。
+

          
+
*降順でのソート [#SortDescending]
+
ここでは降順(大きい順)でのソートについて、いくつかの方法を見ていきます。
+

          
+
**Sort + Reverse [#SortReverse]
+
1つ目は、Sortメソッドで昇順にソートしてから、Reverseメソッドで逆順(つまり降順)にするものです。 配列・ArrayList・List<T>にはそれぞれ&msdn(netfx,member,System.Array.Reverse){Array.Reverse};, &msdn(netfx,member,System.Collections.ArrayList.Reverse){ArrayList.Reverse};, &msdn(netfx,member,System.Collections.Generic.List`1.Reverse){List.Reverse};の各メソッドが用意されていて、これを使うことで要素を逆順に並び替える事が出来ます。 なお、これらのメソッドはSortメソッドと同様、元になった配列・コレクション自体の内容を逆順にします。
+

          
+
#tabpage(C#)
+
#code(cs,配列を降順にソートする){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象の配列
+
    int[] arr = new int[] {5, 2, 3, 1, 4};
+

          
+
    // ソート
+
    Array.Sort(arr);
+

          
+
    // リバース
+
    Array.Reverse(arr);
+

          
+
    foreach (int val in arr) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+

          
+
#code(cs,Listを降順にソートする){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のList<int>
+
    List<int> list = new List<int>(new int[] {5, 2, 3, 1, 4});
+

          
+
    // ソート
+
    list.Sort();
+

          
+
    // リバース
+
    list.Reverse();
+

          
+
    foreach (int val in list) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,配列を降順にソートする){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象の配列
+
    Dim arr() As Integer = New Integer() {5, 2, 3, 1, 4}
+

          
+
    ' ソート
+
    Array.Sort(arr)
+

          
+
    ' リバース
+
    Array.Reverse(arr)
+

          
+
    For Each val As Integer In arr
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+

          
+
#code(vb,Listを降順にソートする){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のList(Of Integer)
+
    Dim list As New List(Of Integer)(New Integer() {5, 2, 3, 1, 4})
+

          
+
    ' ソート
+
    list.Sort()
+

          
+
    ' リバース
+
    list.Reverse()
+

          
+
    For Each val As Integer In list
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
5, 4, 3, 2, 1, 
+
}}
+

          
+
**Sort + Comparison<T> [#DescendingComparison]
+
2つ目は、Sortメソッドと&msdn(netfx,type,System.Comparison`1){Comparision<T>デリゲート};を組み合わせる方法です。 Sortメソッドに特に引数を指定しない場合、デフォルト(つまり昇順)の並び替え順序でソートします。 Sortメソッドの引数に並び替え順序を定義したメソッドを表すComparisionデリゲートを指定すると、その順序に従ってソートするようになります。 よって、降順に並び替えるよう動作を定義するメソッドを用意してSortメソッドに渡すことで、降順にソートする事ができます。 なお、この方法はComparisionデリゲートを引数にとることが出来る&msdn(netfx,member,System.Array.Sort){Array.Sortメソッド};と&msdn(netfx,member,System.Collections.Generic.List`1.Sort){List.Sortメソッド};で使うことが出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  // 二つのintを比較するためのメソッド
+
  static int CompareDescending(int x, int y)
+
  {
+
    return y.CompareTo(x);
+
    // 単に次のようにしても同じ
+
    // return y - x;
+
    // return -x.CompareTo(y);
+

          
+
    // 参考までに、昇順の場合は次のように記述する
+
    // return x.CompareTo(y);
+
    // return x - y;
+
  }
+

          
+
  static void Main()
+
  {
+
    // ソート対象のList<int>
+
    List<int> list = new List<int>(new int[] {5, 2, 3, 1, 4});
+

          
+
    // ソート
+
    list.Sort(CompareDescending);
+

          
+
    foreach (int val in list) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  ' 二つのIntegerを比較するためのメソッド
+
  Shared Function CompareDescending(ByVal x As Integer, ByVal y As Integer) As Integer
+
    Return y.CompareTo(x)
+
    ' 単に次のようにしても同じ
+
    ' Return y - x
+
    ' Return -x.CompareTo(y)
+

          
+
    ' 参考までに、昇順の場合は次のように記述する
+
    ' Return x.CompareTo(y)
+
    ' Return x - y
+
  End Function
+

          
+
  Shared Sub Main()
+
    ' ソート対象のList(Of Integer)
+
    Dim list As New List(Of Integer)(New Integer() {5, 2, 3, 1, 4})
+

          
+
    ' ソート
+
    list.Sort(AddressOf CompareDescending)
+

          
+
    ' 降順にソートして表示
+
    For Each val As Integer In list
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
5, 4, 3, 2, 1, 
+
}}
+

          
+
SortメソッドとComparision<T>デリゲートについては、[[複合型のソート>#SortCompositeType]]でも改めて解説します。
+

          
+
**OrderByDescending [#Enumerable.OrderByDescending]
+
3つ目は、拡張メソッドである&msdn(netfx,member,System.Core.dll,System.Linq.Enumerable.OrderByDescending){OrderByDescendingメソッド};を使う方法です。 [[既に解説したOrderByメソッド>#Enumerable.OrderBy]]は配列・コレクションを昇順にソートするものでしたが、OrderByDescendingメソッドは降順にソートするものです。
+

          
+
#tabpage(C#)
+
#code(cs,配列を降順にソートする){{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象の配列
+
    int[] arr = new int[] {5, 2, 3, 1, 4};
+

          
+
    // 降順にソートして表示
+
    foreach (int val in arr.OrderByDescending(val => val)) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+

          
+
#code(cs,Listを降順にソートする){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ソート対象のList<int>
+
    List<int> list = new List<int>(new int[] {5, 2, 3, 1, 4});
+

          
+
    // 降順にソートして表示
+
    foreach (int val in list.OrderByDescending(val => val)) {
+
      Console.Write("{0}, ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,配列を降順にソートする){{
+
Imports System
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象の配列
+
    Dim arr() As Integer = New Integer() {5, 2, 3, 1, 4}
+

          
+
    ' 降順にソートして表示
+
    For Each val As Integer In arr.OrderByDescending(Function(e) e)
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+

          
+
#code(vb,Listを降順にソートする){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ソート対象のList(Of Integer)
+
    Dim list As New List(Of Integer)(New Integer() {5, 2, 3, 1, 4})
+

          
+
    ' 降順にソートして表示
+
    For Each val As Integer In list.OrderByDescending(Function(e) e)
+
      Console.Write("{0}, ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
5, 4, 3, 2, 1, 
+
}}
+

          
+
OrderByDescendingメソッドは、降順にソートされる点以外はOrderByメソッドと同じなので、詳しくは[[OrderByメソッドについての解説>#Enumerable.OrderBy]]を参照してください。
+

          
+
*複合型のソート [#SortCompositeType]
+
**Sort + Comparison<T>
+
数値や文字列などの型は、あらかじめデフォルトの並べ替え順序が定義されているため特に何も指定しなくてもソート出来ますが、独自に定義したクラス・構造体などの複合型の場合は並べ替え順序を定義しない限りソートすることが出来ません(この点については、[[programming/netfx/comparison/0_comparison]]で詳しく解説しています)。
+

          
+
[[降順でのソート>#DescendingComparison]]でも述べたとおり、&msdn(netfx,member,System.Array.Sort){Array.Sortメソッド};および&msdn(netfx,member,System.Collections.Generic.List`1.Sort){List.Sortメソッド};では、並び替え順序を定義したメソッドを用意し、それを&msdn(netfx,type,System.Comparison`1){Comparision<T>デリゲート};としてSortメソッドの引数に指定することにより、デフォルト(昇順)以外の順序、独自に定義した順序でソートすることが出来ます。
+

          
+
早速、独自に定義したクラスをソートする方法、並べ替え順序を定義する方法について順を追って見ていきます。 ここではNameフィールド(string)とIDフィールド(int)を持つクラスAccountを作成し、Accountクラスのインスタンスが格納されたリストをID順にソートすることにします。 具体的には、次のコードでソートが出来るように実装していきます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Account {
+
  public int ID;
+
  public string Name;
+

          
+
  public Account(int id, string name)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
  }
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    List<Account> list = new List<Account>(new Account[] {
+
      new Account(3, "Bob"),
+
      new Account(1, "Dave"),
+
      new Account(2, "Alice"),
+
      new Account(5, "Charlie"),
+
      new Account(4, "Eve"),
+
    });
+

          
+
    // このままではソート出来ない (InvalidOperationExceptionがスローされる)
+
    // list.Sort();
+

          
+
    foreach (Account a in list) {
+
      Console.WriteLine("{0} {1}", a.ID, a.Name);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Public ID As Integer
+
  Public Name As String
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String)
+
    MyClass.ID = id
+
    MyClass.Name = name
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of Account)(New Account() { _
+
      New Account(3, "Bob"), _
+
      New Account(1, "Dave"), _
+
      New Account(2, "Alice"), _
+
      New Account(5, "Charlie"), _
+
      New Account(4, "Eve") _
+
    })
+

          
+
    ' このままではソート出来ない (InvalidOperationExceptionがスローされる)
+
    ' list.Sort()
+

          
+
    For Each a As Account In list
+
      Console.WriteLine("{0} {1}", a.ID, a.Name)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
まずは、並べ替え順序を定義をするために、比較を行うメソッドを用意します。 このメソッドは、Comparision<T>デリゲートの形でSortメソッドに渡す必要があります。 Comparison<T>デリゲートの形式を見てみると、次のようになっています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
public delegate int Comparison<in T>(T x, T y);
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Public Delegate Function Comparison(Of In T)(x As T, y As T) As Integer
+
}}
+
#tabpage-end
+

          
+
この形式を分かりやすく説明すると、「ある型Tの要素二つを比べて、どちらが小さいか・大きいかを数値として返す」というものです。 Sortメソッドの内部では、各要素の比較が行われる度にこのメソッドが呼び出され、戻り値として返される大小関係によって要素の並べ替えが行われることになります。 この形式にあわせて、Accountクラスを比較するメソッドCompareAccountを作成すると次のようになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
static int CompareAccount(Account x, Account y)
+
{
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
End Function
+
}}
+
#tabpage-end
+

          
+
次にこのメソッドを実装します。 比較を行うメソッドでは二つの要素の大小関係を戻り値として返します。 具体的には、引数として渡される二つの要素&var{x};と&var{y};について、その大小関係が
+
-&var{x}; > &var{y}; (&var{x};が&var{y};より大きい) ならば 正の数
+
-&var{x}; < &var{y}; (&var{x};が&var{y};より小さい) ならば 負の数
+
-&var{x}; = &var{y}; (&var{x};と&var{y};が等しい) ならば 0
+

          
+
を返すようにします。 このルールに従ってメソッドを実装すると、次のようになります。 正の数・負の数ならなんでもよいので、ここではそれぞれ1と-1を返しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
static int CompareAccount(Account x, Account y)
+
{
+
  if (x > y)
+
    return 1;
+
  else if (x < y)
+
    return -1;
+
  else // if (x == y)
+
    return 0;
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
  If x > y Then
+
    Return 1
+
  Else If x < y
+
    Return -1
+
  Else ' If x = y
+
    Return 0
+
  End If
+
End Function
+
}}
+
#tabpage-end
+

          
+
当然Accountクラスのインスタンスそのものを比較することはできないため、このままでは不十分です。 ここではID順でのソートを行いたいため、インスタンスの大小関係がIDフィールドの値によって定まるように実装します。 最終的に、ID順でソートするためのメソッドCompareAccountは次のようになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
static int CompareAccount(Account x, Account y)
+
{
+
  if (x.ID > y.ID)
+
    return 1;
+
  else if (x.ID < y.ID)
+
    return -1;
+
  else // if (x.ID == y.ID)
+
    return 0;
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
  If x.ID > y.ID Then
+
    Return 1
+
  Else If x.ID < y.ID
+
    Return -1
+
  Else ' If x.ID = y.ID
+
    Return 0
+
  End If
+
End Function
+
}}
+
#tabpage-end
+

          
+
最後に、このメソッドをSortメソッドの引数として渡せば、リストはこのメソッドで定義された順序、すなわちID順にソートされるようになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Account {
+
  public int ID;
+
  public string Name;
+

          
+
  public Account(int id, string name)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
  }
+
}
+

          
+
class Sample {
+
  static int CompareAccount(Account x, Account y)
+
  {
+
    if (x.ID > y.ID)
+
      return 1;
+
    else if (x.ID < y.ID)
+
      return -1;
+
    else // if (x.ID == y.ID)
+
      return 0;
+
  }
+

          
+
  static void Main()
+
  {
+
    List<Account> list = new List<Account>(new Account[] {
+
      new Account(3, "Bob"),
+
      new Account(1, "Dave"),
+
      new Account(2, "Alice"),
+
      new Account(5, "Charlie"),
+
      new Account(4, "Eve"),
+
    });
+

          
+
    // ソート
+
    list.Sort(CompareAccount);
+

          
+
    foreach (Account a in list) {
+
      Console.WriteLine("{0} {1}", a.ID, a.Name);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Public ID As Integer
+
  Public Name As String
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String)
+
    MyClass.ID = id
+
    MyClass.Name = name
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
    If x.ID > y.ID Then
+
      Return 1
+
    Else If x.ID < y.ID
+
      Return -1
+
    Else ' If x.ID = y.ID
+
      Return 0
+
    End If
+
  End Function
+

          
+
  Shared Sub Main()
+
    Dim list As New List(Of Account)(New Account() { _
+
      New Account(3, "Bob"), _
+
      New Account(1, "Dave"), _
+
      New Account(2, "Alice"), _
+
      New Account(5, "Charlie"), _
+
      New Account(4, "Eve") _
+
    })
+

          
+
    ' ソート
+
    list.Sort(AddressOf CompareAccount)
+

          
+
    For Each a As Account In list
+
      Console.WriteLine("{0} {1}", a.ID, a.Name)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
1 Dave
+
2 Alice
+
3 Bob
+
4 Eve
+
5 Charlie
+
}}
+

          
+
名前順にソートしたければ、Nameフィールドの値を比較するようにCompareAccountメソッドの実装を変えるだけで出来ます。 なお、文字列の比較はその都度定義しなくても、既に用意されている&msdn(netfx,member,System.String.Compare){String.Compareメソッド};を使うことが出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
static int CompareAccount(Account x, Account y)
+
{
+
  return string.Compare(x.Name, y.Name);
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
  Return String.Compare(x.Name, y.Name)
+
End Function
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
2 Alice
+
3 Bob
+
5 Charlie
+
1 Dave
+
4 Eve
+
}}
+

          
+
このように、並べ替え順序(大小関係)を定義することができ、Comparison<T>デリゲートの形式でSortメソッドに渡すことができれば、どのような複合型でもソートを行うことが出来るようになります。
+

          
+
なお、ここまでは昇順となるようにしてきましたが、降順にしたければCompareAccountで定義する大小関係を逆にするか、Reverseメソッドを使ってソートした後で逆順にするだけです。
+

          
+
**OrderBy
+
複合型は複数の基本型からなるため、多くの場合、複合型のソートで実際にキーとして選ばれるのは単純型のメンバとなります。 また、単純型のソートの場合でも、単に昇順・降順でのソートで十分な場合がほとんどで、独自の並び替え順序が必要になる事は少ないです。
+

          
+
OrderByメソッドは、複合型をソートしたい場合でもキーとなるメンバを選択するだけでソートすることが出来、また選択したキーが単純型であれば並べ替え順序を定義する必要もないため、手早くソートを行うことが出来ます。
+

          
+
[[OrderByメソッドの詳細とキーの選択>#Enumerable.OrderBy]]については既に解説しているので省略しますが、先に挙げた例をOrderByメソッドでソートするようにすると、以下のようになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Account {
+
  public int ID;
+
  public string Name;
+

          
+
  public Account(int id, string name)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
  }
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    List<Account> list = new List<Account>(new Account[] {
+
      new Account(3, "Bob"),
+
      new Account(1, "Dave"),
+
      new Account(2, "Alice"),
+
      new Account(5, "Charlie"),
+
      new Account(4, "Eve"),
+
    });
+

          
+
    // IDでソート
+
    IOrderedEnumerable<Account> sorted = list.OrderBy(a => a.ID);
+
    // Nameでソートする場合
+
    //IOrderedEnumerable<Account> sorted = list.OrderBy(a => a.Name);
+

          
+
    foreach (Account a in sorted) {
+
      Console.WriteLine("{0} {1}", a.ID, a.Name);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Account
+
  Public ID As Integer
+
  Public Name As String
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String)
+
    MyClass.ID = id
+
    MyClass.Name = name
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of Account)(New Account() { _
+
      New Account(3, "Bob"), _
+
      New Account(1, "Dave"), _
+
      New Account(2, "Alice"), _
+
      New Account(5, "Charlie"), _
+
      New Account(4, "Eve") _
+
    })
+

          
+
    ' IDでソート
+
    Dim sorted As IOrderedEnumerable(Of Account) = list.OrderBy(Function(a) a.ID)
+
    ' Nameでソートする場合
+
    'Dim sorted As IOrderedEnumerable(Of Account) = list.OrderBy(Function(a) a.Name)
+

          
+
    For Each a As Account In sorted
+
      Console.WriteLine("{0} {1}", a.ID, a.Name)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
1 Dave
+
2 Alice
+
3 Bob
+
4 Eve
+
5 Charlie
+
}}
+

          
+
また、OrderByメソッドの代わりに[[OrderByDescendingメソッド>#Enumerable.OrderByDescending]]を使うことで降順にソートすることが出来ます。
+

          
+
*複数キーでのソート
+
**Sort + Comparison<T>
+
これまでの例では、並べ替え順序を定義する際に単一のキーのみを用いていましたが、並べ替え順序の定義を拡張することで複数のキーでソートできるようになります。 複数のキーでソートするには、まず第一のキーで比較し、同じだった場合は第二のキーで比較するように並べ替え順序を定義することで実現できます。
+

          
+
まず、一つのキーでソートする場合について振り返ると、比較を行うメソッドでは引数として渡される二つの要素&var{x};と&var{y};について、その大小関係に従って
+
-&var{x}; > &var{y}; ならば 正の数
+
-&var{x}; < &var{y}; ならば 負の数
+
-&var{x}; = &var{y}; ならば 0
+

          
+
を返すように実装する必要がありました。 二つのキーでソートする場合は、要素&var{x};と&var{y};についてまず第一のキーで比較を行い、第一のキーが同じだった場合は第二のキーで比較するようにします。 つまり、上記の条件式を拡張して、比較を行うメソッドでは
+
-第一のキーについて &var{x}; > &var{y}; (&var{x.Key1}; > &var{y.Key1};) ならば 正の数
+
-第一のキーについて &var{x}; < &var{y}; (&var{x.Key1}; < &var{y.Key1};) ならば 負の数
+
-第一のキーについて &var{x}; = &var{y}; (&var{x.Key1}; = &var{y.Key1};) ならば さらに第二のキーで比較する
+
--第二のキーについて &var{x}; > &var{y}; (&var{x.Key2}; > &var{y.Key2};) ならば 正の数
+
--第二のキーについて &var{x}; < &var{y}; (&var{x.Key2}; < &var{y.Key2};) ならば 負の数
+
--第二のキーについて &var{x}; < &var{y}; (&var{x.Key2}; = &var{y.Key2};) ならば 0
+

          
+
を返すように実装します。 これにより、各要素はまず第一のキーの順に並べ替えられ、第一のキーが同じ要素については第二のキーの順に並べ替えられるようになり、二つのキーでソートされることになります。
+

          
+
具体例を見ていきます。 次の例では、ID(int)、名前(string)、年齢(int)のフィールドを持つAccountクラスとそれを格納するリストを作成し、ソートしています。 ここでは第一のキーを年齢、第二のキーをIDとし、年齢が若い順、年齢が同じ場合はIDが小さい順にソートしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Account {
+
  public int ID;
+
  public string Name;
+
  public int Age;
+

          
+
  public Account(int id, string name, int age)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
    this.Age = age;
+
  }
+
}
+

          
+
class Sample {
+
  static int CompareAccount(Account x, Account y)
+
  {
+
    // 第一のキー(Ageフィールド)で比較
+
    if (x.Age > y.Age) {
+
      return 1;
+
    }
+
    else if (x.Age < y.Age) {
+
      return -1;
+
    }
+
    else /* if (x.Age == y.Age) */ {
+
      // 第一のキーが同じだった場合は、第二のキー(IDフィールド)で比較
+
      if (x.ID > y.ID)
+
        return 1;
+
      else if (x.ID < y.ID)
+
        return -1;
+
      else // if (x.ID == y.ID)
+
        return 0;
+
    }
+
  }
+

          
+
  static void Main()
+
  {
+
    List<Account> list = new List<Account>(new Account[] {
+
      new Account(3, "Bob", 16),
+
      new Account(1, "Dave", 25),
+
      new Account(2, "Alice", 16),
+
      new Account(5, "Charlie", 9),
+
      new Account(4, "Eve", 16),
+
      new Account(6, "Romeo", 9),
+
      new Account(7, "Juliet", 25),
+
    });
+

          
+
    // ソート
+
    list.Sort(CompareAccount);
+

          
+
    foreach (Account a in list) {
+
      Console.WriteLine("{0} {1,-8} {2}", a.ID, a.Name, a.Age);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Public ID As Integer
+
  Public Name As String
+
  Public Age As Integer
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String, ByVal age As Integer)
+
    MyClass.ID = id
+
    MyClass.Name = name
+
    Myclass.Age = age
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
    ' 第一のキー(Ageフィールド)で比較
+
    If x.Age > y.Age Then
+
      Return 1
+
    Else If x.Age < y.Age Then
+
      Return -1
+
    Else ' If x.Age = y.Age Then
+
      ' 第一のキーが同じだった場合は、第二のキー(IDフィールド)で比較
+
      If x.ID > y.ID Then
+
        Return 1
+
      Else If x.ID < y.ID Then
+
        Return -1
+
      Else ' If x.ID = y.ID Then
+
        Return 0
+
      End If
+
    End If
+
  End Function
+

          
+
  Shared Sub Main()
+
    Dim list As New List(Of Account)(New Account() { _
+
      New Account(3, "Bob", 16), _
+
      New Account(1, "Dave", 25), _
+
      New Account(2, "Alice", 16), _
+
      New Account(5, "Charlie", 9), _
+
      New Account(4, "Eve", 16), _
+
      New Account(6, "Romeo", 9), _
+
      New Account(7, "Juliet", 25) _
+
    })
+

          
+
    ' ソート
+
    list.Sort(AddressOf CompareAccount)
+

          
+
    For Each a As Account In list
+
      Console.WriteLine("{0} {1,-8} {2}", a.ID, a.Name, a.Age)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
5 Charlie  9
+
6 Romeo    9
+
2 Alice    16
+
3 Bob      16
+
4 Eve      16
+
1 Dave     25
+
7 Juliet   25
+
}}
+

          
+
次に上記の例を少し変えて、名前を第一のキー、IDを第二のキーとしてソートしてみます。 文字列の比較には&msdn(netfx,member,System.String.Compare){String.Compareメソッド};が使えます。 このメソッドも引数の大小関係に応じて正の数・負の数・0のいずれかが返されます。 同じ場合には0となるので、戻り値が0の場合は第二のキーで比較するようにします。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Account {
+
  public int ID;
+
  public string Name;
+
  public int Age;
+

          
+
  public Account(int id, string name, int age)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
    this.Age = age;
+
  }
+
}
+

          
+
class Sample {
+
  static int CompareAccount(Account x, Account y)
+
  {
+
    // 第一のキー(Nameフィールド)で比較
+
    int compareName = string.Compare(x.Name, y.Name);
+

          
+
    if (compareName == 0) {
+
      // x.Name == y.Nameだった場合、第二のキー(IDフィールド)で比較する
+
      if (x.ID > y.ID)
+
        return 1;
+
      else if (x.ID < y.ID)
+
        return -1;
+
      else // if (x.ID == y.ID)
+
        return 0;
+
    }
+
    else {
+
      // x.Name > y.Nameもしくはx.Name < y.Nameだった場合、比較結果をそのまま返す
+
      return compareName;
+
    }
+
  }
+

          
+
  static void Main()
+
  {
+
    List<Account> list = new List<Account>(new Account[] {
+
      new Account(3, "Alice", 16),
+
      new Account(1, "Bob", 25),
+
      new Account(2, "Alice", 16),
+
      new Account(5, "Charlie", 9),
+
      new Account(4, "Bob", 16),
+
      new Account(6, "Alice", 9),
+
      new Account(7, "Charlie", 25),
+
    });
+

          
+
    // ソート
+
    list.Sort(CompareAccount);
+

          
+
    foreach (Account a in list) {
+
      Console.WriteLine("{0} {1,-8} {2}", a.ID, a.Name, a.Age);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Public ID As Integer
+
  Public Name As String
+
  Public Age As Integer
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String, ByVal age As Integer)
+
    MyClass.ID = id
+
    MyClass.Name = name
+
    Myclass.Age = age
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Function CompareAccount(ByVal x As Account, ByVal y As Account) As Integer
+
    ' 第一のキー(Nameフィールド)で比較
+
    Dim compareName As Integer = String.Compare(x.Name, y.Name)
+

          
+
    If compareName = 0 Then
+
      ' x.Name = y.Nameだった場合、第二のキー(IDフィールド)で比較する
+
      If x.ID > y.ID Then
+
        Return 1
+
      Else If x.ID < y.ID Then
+
        Return -1
+
      Else ' If x.ID = y.ID Then
+
        Return 0
+
      End If
+
    Else
+
      ' x.Name > y.Nameもしくはx.Name < y.Nameだった場合、比較結果をそのまま返す
+
      Return compareName
+
    End If
+
  End Function
+

          
+
  Shared Sub Main()
+
    Dim list As New List(Of Account)(New Account() { _
+
      New Account(3, "Alice", 16), _
+
      New Account(1, "Bob", 25), _
+
      New Account(2, "Alice", 16), _
+
      New Account(5, "Charlie", 9), _
+
      New Account(4, "Bob", 16), _
+
      New Account(6, "Alice", 9), _
+
      New Account(7, "Charlie", 25) _
+
    })
+

          
+
    ' ソート
+
    list.Sort(AddressOf CompareAccount)
+

          
+
    For Each a As Account In list
+
      Console.WriteLine("{0} {1,-8} {2}", a.ID, a.Name, a.Age)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
2 Alice    16
+
3 Alice    16
+
6 Alice    9
+
1 Bob      25
+
4 Bob      16
+
5 Charlie  9
+
7 Charlie  25
+
}}
+

          
+
ここまではキーが二つの場合を例示しましたが、さらに多くのキーでソートしたければ、第二のキーで比較して同じなら第三のキー、第三のキーで比較して同じなら第四のキーと、比較処理を次々拡張することで実現できます。
+

          
+
**OrderBy + ThenBy [#Enumerable.ThenBy]
+
[[既に解説したOrderByメソッドでのソート>#Enumerable.OrderBy]]では単一のキーでしかソート出来ませんが、&msdn(netfx,member,System.Core.dll,System.Linq.Enumerable.ThenBy){ThenByメソッド};と組み合わせて使うと、複数のキーでのソートが出来るようになります。 ThenByメソッドは、OrderByメソッドの戻り値である&msdn(netfx,type,System.Linq.IOrderedEnumerable`1){IOrderedEnumerable<TSource>};に対する拡張メソッドであり、OrderByメソッドの結果(単一のキーでソートした結果)に対してThenByメソッドを呼び出すことにより、第二のキーでソートした結果を得ることが出来ます。
+

          
+
さらにThenByメソッドの戻り値もIOrderedEnumerable<TSource>であるため、ThenByメソッドの戻り値に対してThenByメソッドを呼び出すと、第三のキーでソートした結果を得られるため、キーの数に応じて重ねてThenByメソッドを呼び出すことで複数キーでのソートを行うことが出来ます。
+

          
+
早速、具体例を見ていきます。 次の例では、ID(int)、名前(string)、年齢(int)のフィールドを持つAccountクラスとそれを格納するリストを作成し、ソートしています。 ここでは第一のキーを年齢、第二のキーをIDとし、年齢が若い順、年齢が同じ場合はIDが小さい順にソートしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Account {
+
  public int ID;
+
  public string Name;
+
  public int Age;
+

          
+
  public Account(int id, string name, int age)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
    this.Age = age;
+
  }
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    List<Account> list = new List<Account>(new Account[] {
+
      new Account(3, "Bob", 16),
+
      new Account(1, "Dave", 25),
+
      new Account(2, "Alice", 16),
+
      new Account(5, "Charlie", 9),
+
      new Account(4, "Eve", 16),
+
      new Account(6, "Romeo", 9),
+
      new Account(7, "Juliet", 25),
+
    });
+

          
+
    // ソート
+
    IOrderedEnumerable<Account> sorted = list.OrderBy(a => a.Age).ThenBy(a => a.ID);
+

          
+
    foreach (Account a in sorted) {
+
      Console.WriteLine("{0} {1,-8} {2}", a.ID, a.Name, a.Age);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Public ID As Integer
+
  Public Name As String
+
  Public Age As Integer
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String, ByVal age As Integer)
+
    MyClass.ID = id
+
    MyClass.Name = name
+
    Myclass.Age = age
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of Account)(New Account() { _
+
      New Account(3, "Bob", 16), _
+
      New Account(1, "Dave", 25), _
+
      New Account(2, "Alice", 16), _
+
      New Account(5, "Charlie", 9), _
+
      New Account(4, "Eve", 16), _
+
      New Account(6, "Romeo", 9), _
+
      New Account(7, "Juliet", 25) _
+
    })
+

          
+
    ' ソート
+
    Dim sorted As IOrderedEnumerable(Of Account) = list.OrderBy(Function(a) a.Age).ThenBy(Function(a) a.ID)
+

          
+
    For Each a As Account In sorted
+
      Console.WriteLine("{0} {1,-8} {2}", a.ID, a.Name, a.Age)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
5 Charlie  9
+
6 Romeo    9
+
2 Alice    16
+
3 Bob      16
+
4 Eve      16
+
1 Dave     25
+
7 Juliet   25
+
}}
+

          
+
なお、OrderByメソッドと同様、ThenByメソッドも''遅延実行''されるため、戻り値に対してforeach等で列挙操作を行うことで初めてソートが行われる点に注意してください。
+

          
+
*ソートとその他留意事項等
+
**大文字小文字の考慮
+
文字列をソートする際、場合によっては大文字小文字の違いをどう扱うか厳密に決める必要が出て来ます。 その場合は、&msdn(netfx,type,System.StringComparer){StringComparer};を使ってどう扱うかを指定することができます。 Sortメソッド、OrderByメソッドともにIComparerを引数に取ることができ、これにStringComparerを指定することで、文字列比較の際の動作を指定できます。
+

          
+
#tabpage(C#)
+
#code(cs,Sort + IComparer){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    List<string> list = new List<string>(new string[] {
+
      "ab", "ABC", "AA", "a", "aa", "abc", "A",
+
    });
+

          
+
    // 大文字・小文字の違いを無視してソート
+
    list.Sort(StringComparer.OrdinalIgnoreCase);
+

          
+
    foreach (string s in list) {
+
      Console.Write("{0} ", s);
+
    }
+
    Console.WriteLine();
+

          
+
    // 大文字・小文字の違いを意識してソート
+
    list.Sort(StringComparer.Ordinal);
+

          
+
    foreach (string s in list) {
+
      Console.Write("{0} ", s);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+

          
+
#code(cs,OrderBy + IComparer){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    List<string> list = new List<string>(new string[] {
+
      "ab", "ABC", "AA", "a", "aa", "abc", "A",
+
    });
+

          
+
    // 大文字・小文字の違いを無視してソート
+
    foreach (string s in list.OrderBy(s => s, StringComparer.OrdinalIgnoreCase)) {
+
      Console.Write("{0} ", s);
+
    }
+
    Console.WriteLine();
+

          
+
    // 大文字・小文字の違いを意識してソート
+
    foreach (string s in list.OrderBy(s => s, StringComparer.Ordinal)) {
+
      Console.Write("{0} ", s);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,Sort + IComparer){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of String)(New String() { _
+
      "ab", "ABC", "AA", "a", "aa", "abc", "A" _
+
    })
+

          
+
    ' 大文字・小文字の違いを無視してソート
+
    list.Sort(StringComparer.OrdinalIgnoreCase)
+

          
+
    For Each s As String In list
+
      Console.Write("{0} ", s)
+
    Next
+
    Console.WriteLine()
+

          
+
    ' 大文字・小文字の違いを意識してソート
+
    list.Sort(StringComparer.Ordinal)
+

          
+
    For Each s As String In list
+
      Console.Write("{0} ", s)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+

          
+
#code(vb,OrderBy + IComparer){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of String)(New String() { _
+
      "ab", "ABC", "AA", "a", "aa", "abc", "A" _
+
    })
+

          
+
    ' 大文字・小文字の違いを無視してソート
+
    For Each str As String In list.OrderBy(Function(s) s, StringComparer.OrdinalIgnoreCase)
+
      Console.Write("{0} ", str)
+
    Next
+
    Console.WriteLine()
+

          
+
    ' 大文字・小文字の違いを意識してソート
+
    For Each str As String In list.OrderBy(Function(s) s, StringComparer.Ordinal)
+
      Console.Write("{0} ", str)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
a A aa AA ab abc ABC 
+
A AA ABC a aa ab abc 
+
}}
+

          
+
なお、IComparerについては[[programming/netfx/comparison/0_comparison]]、StringComparerについて[[programming/netfx/string/2_2_compareoptions]]で詳しく解説しています。
+

          
+
**OrderByと元のコレクションへの変更
+
OrderByメソッド・ThenByメソッドは''遅延実行''されるため、メソッドを呼び出した時点では結果は確定していません。 戻り値を列挙する(もしくは配列・リストに変換する)時点ではじめて結果が確定します。 次の例のように、OrderByメソッドを呼び出した後に元のコレクションに変更を加えると、その変更はソート後の結果にも影響するという点に注意が必要です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    List<int> list = new List<int>(new int[] {
+
      3, 1, 2,
+
    });
+

          
+
    // ソート(この時点では結果が確定していない点に注意)
+
    IOrderedEnumerable<int> sorted = list.OrderBy(val => val);
+

          
+
    // 元になったリストに変更を加える
+
    list.RemoveAt(0);
+
    list.Add(5);
+
    list.Add(4);
+

          
+
    // 列挙して結果を表示
+
    foreach (int val in sorted) {
+
      Console.Write("{0} ", val);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of Integer)(New Integer() { _
+
      3, 1, 2 _
+
    })
+

          
+
    ' ソート(この時点では結果が確定していない点に注意)
+
    Dim sorted As IOrderedEnumerable(Of Integer) = list.OrderBy(Function(val) val)
+

          
+
    ' 元になったリストに変更を加える
+
    list.RemoveAt(0)
+
    list.Add(5)
+
    list.Add(4)
+

          
+
    ' 列挙して結果を表示
+
    For Each val As Integer In sorted
+
      Console.Write("{0} ", val)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
1 2 4 5 
+
}}
+

          
+
**パフォーマンスの比較
+
ここではいくつかのケースについてパフォーマンスの比較を行った結果を紹介します。 比較メソッドの定義方法やソートするデータの種類等によっては結果が変わるので、ここで紹介している結果はあくまで参考程度のものです。
+

          
+
***Sort vs OrderBy
+
SortメソッドとOrderByメソッドを比較すると、OrderByメソッドでは各要素の比較の度にキーの選択が行われる分だけ速度の面で劣るようです。 以下のコードでは、それぞれ100個、10,000個、1,000,000個の要素を持つList<int>に対してSortメソッドとOrderByメソッドでソートし、列挙する操作をそれぞれ3回試行した場合の経過時間を比較しています。
+

          
+
#code(cs,検証に使ったコード){{
+
using System;
+
using System.Collections.Generic;
+
using System.Diagnostics;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Console.WriteLine(Environment.OSVersion);
+
    Console.WriteLine(Environment.Version);
+

          
+
    foreach (var count in new[] {100, 10 * 1000, 1000 * 1000}) {
+
      Console.WriteLine("{0:N0}", count);
+

          
+
      for (var i = 0; i < 3; i++) {
+
        TestSort(CreateSource(count, i));
+
        TestOrderBy(CreateSource(count, i));
+
      }
+
    }
+
  }
+

          
+
  static List<int> CreateSource(int count, int seed)
+
  {
+
    var rand = new Random(seed);
+
    var list = new List<int>();
+

          
+
    for (var i = 0; i < count; i++) {
+
      list.Add(rand.Next());
+
    }
+

          
+
    return list;
+
  }
+

          
+
  static void TestSort(List<int> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    source.Sort();
+

          
+
    foreach (var val in source) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  Sort   : {0}", sw.Elapsed);
+
  }
+

          
+
  static void TestOrderBy(List<int> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    foreach (var val in source.OrderBy(val => val)) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  OrderBy: {0}", sw.Elapsed);
+
  }
+
}
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果 (Windows 7 + .NET Framework 4)){{
+
Microsoft Windows NT 6.1.7601 Service Pack 1
+
4.0.30319.239
+
100
+
  Sort   : 00:00:00.0001313
+
  OrderBy: 00:00:00.0149608
+
  Sort   : 00:00:00.0000150
+
  OrderBy: 00:00:00.0000787
+
  Sort   : 00:00:00.0000159
+
  OrderBy: 00:00:00.0000382
+
10,000
+
  Sort   : 00:00:00.0009744
+
  OrderBy: 00:00:00.0037582
+
  Sort   : 00:00:00.0010783
+
  OrderBy: 00:00:00.0038236
+
  Sort   : 00:00:00.0009956
+
  OrderBy: 00:00:00.0041097
+
1,000,000
+
  Sort   : 00:00:00.1425273
+
  OrderBy: 00:00:01.1132711
+
  Sort   : 00:00:00.1422619
+
  OrderBy: 00:00:01.1064369
+
  Sort   : 00:00:00.1396308
+
  OrderBy: 00:00:01.1138493
+
}}
+

          
+
#prompt(実行結果 (Ubuntu 11.10 + Mono 2.10.6)){{
+
Unix 3.0.0.14
+
4.0.30319.1
+
100
+
  Sort   : 00:00:00.0043755
+
  OrderBy: 00:00:00.0147171
+
  Sort   : 00:00:00.0000182
+
  OrderBy: 00:00:00.0000361
+
  Sort   : 00:00:00.0000169
+
  OrderBy: 00:00:00.0000277
+
10,000
+
  Sort   : 00:00:00.0024438
+
  OrderBy: 00:00:00.0059536
+
  Sort   : 00:00:00.0037272
+
  OrderBy: 00:00:00.0054564
+
  Sort   : 00:00:00.0024618
+
  OrderBy: 00:00:00.0056411
+
1,000,000
+
  Sort   : 00:00:00.3313208
+
  OrderBy: 00:00:01.0688121
+
  Sort   : 00:00:00.3300875
+
  OrderBy: 00:00:01.0192792
+
  Sort   : 00:00:00.3305355
+
  OrderBy: 00:00:01.0644162
+
}}
+

          
+
一方で、複数のキーでソートするのに、Sort(Comparison<T>)メソッドを使った場合とOrderByメソッド+ThenByメソッドを使った場合を比較すると、速度の点では大きな差は無いようです。 以下のコードでは、先と同様100個、10,000個、1,000,000個の要素を持つList<Tuple<int, int>>に対してSort(Comparison<T>)メソッドとOrderByメソッド+ThenByメソッドでソートし、列挙する操作をそれぞれ3回試行した場合の経過時間を比較しています。
+

          
+
#code(cs,検証に使ったコード){{
+
using System;
+
using System.Collections.Generic;
+
using System.Diagnostics;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Console.WriteLine(Environment.OSVersion);
+
    Console.WriteLine(Environment.Version);
+

          
+
    foreach (var count in new[] {100, 10 * 1000, 1000 * 1000}) {
+
      Console.WriteLine("{0:N0}", count);
+

          
+
      for (var i = 0; i < 3; i++) {
+
        TestSortComparison(CreateSource(count, i));
+
        TestOrderByThenBy(CreateSource(count, i));
+
      }
+
    }
+
  }
+

          
+
  static List<Tuple<int, int>> CreateSource(int count, int seed)
+
  {
+
    var rand = new Random(seed);
+
    var list = new List<Tuple<int, int>>();
+

          
+
    for (var i = 0; i < count; i++) {
+
      list.Add(Tuple.Create(rand.Next(), rand.Next()));
+
    }
+

          
+
    return list;
+
  }
+

          
+
  static int Compare(Tuple<int, int> x, Tuple<int, int> y)
+
  {
+
    var ret = x.Item1 - y.Item1;
+

          
+
    return ret == 0 ? x.Item2 - y.Item2 : ret;
+
  }
+

          
+
  static void TestSortComparison(List<Tuple<int, int>> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    source.Sort(Compare);
+

          
+
    foreach (var val in source) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  Sort(Comparison<T>): {0}", sw.Elapsed);
+
  }
+

          
+
  static void TestOrderByThenBy(List<Tuple<int, int>> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    foreach (var val in source.OrderBy(val => val.Item1).ThenBy(val => val.Item2)) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  OrderBy + ThenBy   : {0}", sw.Elapsed);
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果 (Windows 7 + .NET Framework 4)){{
+
Microsoft Windows NT 6.1.7601 Service Pack 1
+
4.0.30319.239
+
100
+
  Sort(Comparison<T>): 00:00:00.0016116
+
  OrderBy + ThenBy   : 00:00:00.0128862
+
  Sort(Comparison<T>): 00:00:00.0000396
+
  OrderBy + ThenBy   : 00:00:00.0000497
+
  Sort(Comparison<T>): 00:00:00.0000282
+
  OrderBy + ThenBy   : 00:00:00.0000357
+
10,000
+
  Sort(Comparison<T>): 00:00:00.0039588
+
  OrderBy + ThenBy   : 00:00:00.0056537
+
  Sort(Comparison<T>): 00:00:00.0045002
+
  OrderBy + ThenBy   : 00:00:00.0042474
+
  Sort(Comparison<T>): 00:00:00.0038242
+
  OrderBy + ThenBy   : 00:00:00.0048581
+
1,000,000
+
  Sort(Comparison<T>): 00:00:01.0339300
+
  OrderBy + ThenBy   : 00:00:01.4343420
+
  Sort(Comparison<T>): 00:00:01.0314824
+
  OrderBy + ThenBy   : 00:00:01.2782487
+
  Sort(Comparison<T>): 00:00:01.0515235
+
  OrderBy + ThenBy   : 00:00:01.5493575
+
}}
+

          
+
#prompt(実行結果 (Ubuntu 11.10 + Mono 2.10.6)){{
+
Unix 3.0.0.14
+
4.0.30319.1
+
100
+
  Sort(Comparison<T>): 00:00:00.0013989
+
  OrderBy + ThenBy   : 00:00:00.0164684
+
  Sort(Comparison<T>): 00:00:00.0000365
+
  OrderBy + ThenBy   : 00:00:00.0000487
+
  Sort(Comparison<T>): 00:00:00.0000362
+
  OrderBy + ThenBy   : 00:00:00.0000495
+
10,000
+
  Sort(Comparison<T>): 00:00:00.0070140
+
  OrderBy + ThenBy   : 00:00:00.0058386
+
  Sort(Comparison<T>): 00:00:00.0063343
+
  OrderBy + ThenBy   : 00:00:00.0051259
+
  Sort(Comparison<T>): 00:00:00.0065034
+
  OrderBy + ThenBy   : 00:00:00.0058673
+
1,000,000
+
  Sort(Comparison<T>): 00:00:01.3199098
+
  OrderBy + ThenBy   : 00:00:01.1463424
+
  Sort(Comparison<T>): 00:00:01.2777875
+
  OrderBy + ThenBy   : 00:00:01.1191267
+
  Sort(Comparison<T>): 00:00:01.2825583
+
  OrderBy + ThenBy   : 00:00:01.1213952
+
}}
+

          
+
***Sort+Reverse vs Sort(Comparison<T>) vs OrderByDescending
+
降順でソートするために、次の三つの方法をとり、それぞれの速度を比較してみます。
+
+SortメソッドとReverseメソッドを組み合わせる場合
+
+降順にソートするComparison<T>を指定してSortメソッドを呼び出す場合
+
+OrderByDescendingメソッドを用いる場合
+

          
+
以下のコードでは、それぞれ100個、10,000個、1,000,000個の要素を持つList<int>に対して降順でのソート・列挙の操作をそれぞれ3回試行した場合の経過時間を比較しています。 実装系で結果に違いはあるものの、速度の点ではSort+ReverseおよびSort(Comparison<T>)で大きな差はなく、OrderByDescendingは他と比べるとやや劣るようです。
+

          
+
#code(cs,検証に使ったコード){{
+
using System;
+
using System.Collections.Generic;
+
using System.Diagnostics;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Console.WriteLine(Environment.OSVersion);
+
    Console.WriteLine(Environment.Version);
+

          
+
    foreach (var count in new[] {100, 10 * 1000, 1000 * 1000}) {
+
      Console.WriteLine("{0:N0}", count);
+

          
+
      for (var i = 0; i < 3; i++) {
+
        TestSortReverse(CreateSource(count, i));
+
        TestSortComparison(CreateSource(count, i));
+
        TestOrderByDescending(CreateSource(count, i));
+
      }
+
    }
+
  }
+

          
+
  static List<int> CreateSource(int count, int seed)
+
  {
+
    var rand = new Random(seed);
+
    var list = new List<int>();
+

          
+
    for (var i = 0; i < count; i++) {
+
      list.Add(rand.Next());
+
    }
+

          
+
    return list;
+
  }
+

          
+
  static void TestSortReverse(List<int> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    source.Sort();
+
    source.Reverse();
+

          
+
    foreach (var val in source) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  Sort + Reverse     : {0}", sw.Elapsed);
+
  }
+

          
+
  static void TestSortComparison(List<int> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    source.Sort((x, y) => y - x);
+

          
+
    foreach (var val in source) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  Sort(Comparison<T>): {0}", sw.Elapsed);
+
  }
+

          
+
  static void TestOrderByDescending(List<int> source)
+
  {
+
    var sw = Stopwatch.StartNew();
+

          
+
    foreach (var val in source.OrderByDescending(val => val)) {
+
    }
+

          
+
    sw.Stop();
+

          
+
    Console.WriteLine("  OrderByDescending  : {0}", sw.Elapsed);
+
  }
+
}
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果 (Windows 7 + .NET Framework 4)){{
+
Microsoft Windows NT 6.1.7601 Service Pack 1
+
4.0.30319.239
+
100
+
  Sort + Reverse     : 00:00:00.0001307
+
  Sort(Comparison<T>): 00:00:00.0006023
+
  OrderByDescending  : 00:00:00.0216231
+
  Sort + Reverse     : 00:00:00.0000164
+
  Sort(Comparison<T>): 00:00:00.0000399
+
  OrderByDescending  : 00:00:00.0000463
+
  Sort + Reverse     : 00:00:00.0000100
+
  Sort(Comparison<T>): 00:00:00.0000189
+
  OrderByDescending  : 00:00:00.0000268
+
10,000
+
  Sort + Reverse     : 00:00:00.0015731
+
  Sort(Comparison<T>): 00:00:00.0023103
+
  OrderByDescending  : 00:00:00.0048779
+
  Sort + Reverse     : 00:00:00.0010660
+
  Sort(Comparison<T>): 00:00:00.0025257
+
  OrderByDescending  : 00:00:00.0045271
+
  Sort + Reverse     : 00:00:00.0009719
+
  Sort(Comparison<T>): 00:00:00.0020695
+
  OrderByDescending  : 00:00:00.0047003
+
1,000,000
+
  Sort + Reverse     : 00:00:00.1403080
+
  Sort(Comparison<T>): 00:00:00.3427332
+
  OrderByDescending  : 00:00:01.0785580
+
  Sort + Reverse     : 00:00:00.1400711
+
  Sort(Comparison<T>): 00:00:00.3498478
+
  OrderByDescending  : 00:00:01.0661894
+
  Sort + Reverse     : 00:00:00.1424873
+
  Sort(Comparison<T>): 00:00:00.3463507
+
  OrderByDescending  : 00:00:01.0516224
+
}}
+

          
+
#prompt(実行結果 (Ubuntu 11.10 + Mono 2.10.6)){{
+
Unix 3.0.0.14
+
4.0.30319.1
+
100
+
  Sort + Reverse     : 00:00:00.0047614
+
  Sort(Comparison<T>): 00:00:00.0006060
+
  OrderByDescending  : 00:00:00.0156435
+
  Sort + Reverse     : 00:00:00.0000188
+
  Sort(Comparison<T>): 00:00:00.0000161
+
  OrderByDescending  : 00:00:00.0000431
+
  Sort + Reverse     : 00:00:00.0000171
+
  Sort(Comparison<T>): 00:00:00.0000155
+
  OrderByDescending  : 00:00:00.0000287
+
10,000
+
  Sort + Reverse     : 00:00:00.0025755
+
  Sort(Comparison<T>): 00:00:00.0025991
+
  OrderByDescending  : 00:00:00.0055562
+
  Sort + Reverse     : 00:00:00.0024163
+
  Sort(Comparison<T>): 00:00:00.0032577
+
  OrderByDescending  : 00:00:00.0057701
+
  Sort + Reverse     : 00:00:00.0027872
+
  Sort(Comparison<T>): 00:00:00.0025708
+
  OrderByDescending  : 00:00:00.0065627
+
1,000,000
+
  Sort + Reverse     : 00:00:00.3615682
+
  Sort(Comparison<T>): 00:00:00.3654408
+
  OrderByDescending  : 00:00:00.9620297
+
  Sort + Reverse     : 00:00:00.3455927
+
  Sort(Comparison<T>): 00:00:00.3638741
+
  OrderByDescending  : 00:00:00.9560158
+
  Sort + Reverse     : 00:00:00.3475420
+
  Sort(Comparison<T>): 00:00:00.3706791
+
  OrderByDescending  : 00:00:00.9840878
+
}}
+