配列やListクラスを使う時、中の要素が順番に並びかわっていると扱いやすかったりしますが、そんなときの為に順番を並び替えるメソッドが用意されています。
ListクラスにはSortメソッドがあり、配列の場合は ArrayクラスのSortメソッドを利用します。
Sortメソッドの種類
Sortメソッドには引数が異なるいくつかのメソッドが用意されています。
それぞれの特徴を理解して使いこなしていきましょう。
- Sort() ・・・既定の比較子を使って並べ替え
- Sort(IComparer<T>) ・・・指定したIComparer<T>インターフェースで並べ替え
- Sort(Comparison<T>) ・・・指定したComparison<T>デリゲートで並べ替え
※ListクラスもArrayクラスも使い方はほぼ一緒です
既定の比較子で並べ替え
引数で並べ替える条件を指定しないタイプのメソッドです。
既定の比較子というのは List の各要素が持っている IComparable インターフェースを指しています。
たとえば List<string> のような stringクラスのリストの場合、stringクラスが持つ CompareToメソッドの戻り値を条件にして昇順に並べ替えが行われます。
(IComparableインターフェースを持たないオブジェクトを要素にするListに対してSort()を行うと
例外InvalidOperationExceptionがスローされます)
ちなみに、List<int> や List<double> といったリストは正しく Sort() メソッドを実行できます。
int と System.Int32構造体は同じものなので IComparableインターフェースを持っているのです。
※詳細は「C#のStringとstring、Int32とint 違いは・・・ない!」をご覧ください
以下の例では TestItem というクラスに IComparable<T>インターフェースを実装してソートしています。
public class TestItem : IComparable<TestItem> { public int x; public int y; public int CompareTo(TestItem o) { if (null == o) return 1; if (x < o.x) return -1; if (x > o.x) return 1; if (y < o.y) return -1; if (y > o.y) return 1; return 0; } }
private void Test() { var list = new List<TestItem>(); list.Add(new TestItem() { x = 5, y = 4 }); list.Add(new TestItem() { x = 2, y = 1 }); list.Add(new TestItem() { x = 4, y = 7 }); list.Add(new TestItem() { x = 6, y = 3 }); list.Add(new TestItem() { x = 9, y = 9 }); list.Add(new TestItem() { x = 5, y = 2 }); list.Sort(); foreach (var item in list) { System.Console.WriteLine("X=" + item.x + ",Y=" + item.y); } }
出力結果は以下のようになります。
X=2,Y=1 X=4,Y=7 X=5,Y=2 X=5,Y=4 X=6,Y=3 X=9,Y=9
IComparer<T>インターフェースで並べ替え
上記で使用した IComparable<T>インターフェースと似ていて混乱しそうですが以下の違いがあります。
・IComparable<T>インターフェースは自身と引数のオブジェクトを比較する。
・IComparer<T>インターフェースは引数で渡された2つのオブジェクトを比較する。
以下の例では Listクラスを継承した TestListクラスを作成し、そこに IComparer<T>インターフェースを実装してソートしています。
public class TestItem { public int x; public int y; }
public class TestList : List<TestItem>, IComparer<TestItem> { public int Compare(TestItem o1, TestItem o2) { if ((null == o1) && (null == o2)) return 0; if ((null == o1) && (null != o2)) return -1; if ((null != o1) && (null == o2)) return 1; if (o1.x < o2.x) return -1; if (o1.x > o2.x) return 1; if (o1.y < o2.y) return -1; if (o1.y > o2.y) return 1; return 0; } public void SortXY() { Sort(this); } }
private void Test() { var list = new TestList(); list.Add(new TestItem() { x = 5, y = 4 }); list.Add(new TestItem() { x = 2, y = 1 }); list.Add(new TestItem() { x = 4, y = 7 }); list.Add(new TestItem() { x = 6, y = 3 }); list.Add(new TestItem() { x = 9, y = 9 }); list.Add(new TestItem() { x = 5, y = 2 }); list.SortXY(); foreach (var item in list) { System.Console.WriteLine("X=" + item.x + ",Y=" + item.y); } }
Comparison<T>デリゲートで並べ替え
何度も使い回す並べ替え条件ならインターフェースとして実装するのが良さそうですが、1度限りの並べ替えなら、デリゲートを使う方がお手軽かもしれません。
以下の例では、デリゲートをラムダ式で実装しています。
public class TestItem { public int x; public int y; }
private void Test() { var list = new List<TestItem>(); list.Add(new TestItem() { x = 5, y = 4 }); list.Add(new TestItem() { x = 2, y = 1 }); list.Add(new TestItem() { x = 4, y = 7 }); list.Add(new TestItem() { x = 6, y = 3 }); list.Add(new TestItem() { x = 9, y = 9 }); list.Add(new TestItem() { x = 5, y = 2 }); list.Sort((o1, o2) => { if ((null == o1) && (null == o2)) return 0; if ((null == o1) && (null != o2)) return -1; if ((null != o1) && (null == o2)) return 1; if (o1.x < o2.x) return -1; if (o1.x > o2.x) return 1; if (o1.y < o2.y) return -1; if (o1.y > o2.y) return 1; return 0; }); foreach (var item in list) { System.Console.WriteLine("X=" + item.x + ",Y=" + item.y); } }
※デリゲートの詳細は「C#のデリゲート (delegate) って何?」をご覧ください
※ラムダ式の詳細は「C#のラムダ式【=>】って何?」をご覧ください
関連記事
- C#の値型と参照型の違い
- C#のコンストラクタでオーバーロード
- C#のコンストラクタの継承
- C#のジェネリックを使おう
- C#のデリゲート (delegate) って何?
- C#のデリゲートお手軽にする匿名メソッド
- C#のラムダ式【=>】って何?
- C#で基底クラスのメソッドを置き換えるオーバーライド
- C#でキャストとas演算子を使いこなす
- C#で型を判別するtypeofとis演算子
- C#の値型でもnullを扱えるようにするNullable
- C#のリソース解放にはIDisposableとusingを使おう
- C#のStringとstring、Int32とint 違いは・・・ない!
- C#でasync/awaitを使った非同期処理
- C#で文字列を指定の区切り文字で分割
- C#のstring.Formatで桁数や書式を指定する
- C#の配列やListをソートする
- C#の配列やListを検索する (Find,FindAll,FindIndex)
- C#の配列やListを高速に検索する (BinarySearch)
- C#の配列の中に指定の要素が存在するかを調べる(LINQ Contains)
- C#の配列の中に条件を満たす要素が存在するかを調べる(LINQ Any)
- C#の配列から条件に合う要素を抽出する(LINQ Where)
- C#の配列で要素毎の処理結果を得る(LINQ Select)
- C#の配列を並び替える(LINQ OrderBy,ThenBy)
- C#の配列をグループ毎に処理する(LINQ GroupBy)
- C#の配列を内部結合(INNER JOIN)する(LINQ Join)
- C#の配列から最初の要素を取り出す(LINQ First,FirstOrDefault)
- C#の配列の重複要素を削除する(LINQ Distinct)
- C#でフォルダ内のファイル名一覧を取得する
- C#でテキストファイルを読み込む
- C#でテキストファイルに書き込む
- C#でバイナリファイルを読み込む
- C#でバイナリファイルに書き込む
コメントをお書きください