C#には LINQ というライブラリがあります。
LINQ を使えばコレクション(配列や List クラスなど)に対する処理を簡単に行う事が出来ます。
ここでは、LINQ を使って配列を並び替える方法について解説します。
LINQとは
LINQ は IEnumerable<T>インターフェースへの拡張メソッドとして作られています。
つまり、配列、Listクラス、Dictionaryクラス、ObservableCollectionクラスなどのIEnumerable<T>インターフェースを実装するオブジェクトであればどれでも同じように使用する事ができます。
LINQをつかうには using で System.Linq を参照できるようにしておきましょう。
using System.Linq;
配列を並び替える OrderByメソッド
配列を要素を並び替えるには OrderBy メソッドを使用します。
引数に比較方法を指定しますが、ラムダ式を使って記述するのが簡単で一般的な方法です。
※ラムダ式の詳細は「C#のラムダ式【=>】って何?」をご覧ください
以下の例ではPointオブジェクトが入った配列をX座標で並び替えています。
Point[] testArray = new Point[5]; testArray[0] = new Point(4, 5); testArray[1] = new Point(2, 6); testArray[2] = new Point(1, 6); testArray[3] = new Point(4, 2); testArray[4] = new Point(6, 3); IOrderedEnumerable<Point> testOrderBy = testArray.OrderBy(o => o.X); foreach (Point item in testOrderBy) { Console.WriteLine("X=" + item.X + " Y=" + item.Y); }
OrderByメソッドの引数となるラムダ式では X座標 を戻り値としています。
これは X座標の double型が持っている IComparableインターフェースを使って並び替える事を意味しています。
OrderByメソッドの戻り値はIOrderedEnumerable<T>(IEnumerable<T>の派生クラス)です。
※元の配列の要素がPoint型なのでIOrderedEnumerable<Point>になります
IEnumerable<T>はそのまま foreach 文で利用する事が出来ます。
2番目の比較方法を指定する ThenByメソッド
OrderBy での比較で値が同じ場合、されに別の条件で並び替えたい場合があります。
そのようなケースでは ThenBy メソッドを使用します。
以下の例ではX座標で並び替え、X座標が等しい場合は更にY座標で並び替えています。
Point[] testArray = new Point[5]; testArray[0] = new Point(4, 5); testArray[1] = new Point(2, 6); testArray[2] = new Point(1, 6); testArray[3] = new Point(4, 2); testArray[4] = new Point(6, 3); IOrderedEnumerable<Point> testOrderBy = testArray.OrderBy(o => o.X).ThenBy(o => o.Y); foreach (Point item in testOrderBy) { Console.WriteLine("X=" + item.X + " Y=" + item.Y); }
逆順に並び替える OrderByDescendingメソッド
並びを逆順にしたい場合は OrderByDescendingメソッドや ThenByDescendingメソッドを使用します。
以下の例ではX座標を昇順でソートし、X座標が等しい場合Y座標を降順でソートします。
IEnumerable<Point> testOrderBy = testArray.OrderBy(o => o.X).ThenByDescending(o => o.Y);
独自に並び順にする IComparer<T>インターフェース
独自に細かく並び順を作り込みたい場合は IComperer<T>インターフェースを実装したクラスを作成する事で可能になります。
OrderByメソッドの第2引数に IComperer を指定します。
public class PointXComparer : IComparer<Point> { public int Compare(Point o1, Point o2) { 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; } }
Point[] testArray = new Point[5]; testArray[0] = new Point(4, 5); testArray[1] = new Point(2, 6); testArray[2] = new Point(1, 6); testArray[3] = new Point(4, 2); testArray[4] = new Point(6, 3); var cmp = new PointXComparer(); IOrderedEnumerable<Point> testOrderBy = testArray.OrderBy(o => o, cmp); foreach (Point item in testOrderBy) { Console.WriteLine("X=" + item.X + " Y=" + item.Y); }
LINQは遅延実行される
戻り値が IEnumerable<T> となるメソッドでは、データに対するアクションは行われません。
これらのメソッドはどのような処理をするかというコマンドだけを溜め込んでいるような状態です。
LINQ は foreach 文や ToArrayなどのメソッドを実行する時にデータが作成されます。
このような仕組みによって、複数のLINQメソッドと併用しても高速に結果を得られるようになっています。
関連記事
- 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#でバイナリファイルに書き込む
コメントをお書きください
QlqzzNwr (土曜日, 07 8月 2021 05:23)
1