C#の配列を並び替える(LINQ OrderBy,ThenBy)

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メソッドと併用しても高速に結果を得られるようになっています。

 

関連記事