読者です 読者をやめる 読者になる 読者になる

いろいろ備忘録日記

主に .NET 絡みのメモを公開しています。

Linq入門記-24 (LINQ To Object, OrderBy, OrderByDescending)

C# Linq


OrderBy及びOrderByDescendingは、ともに並び替えを行うクエリ演算子です。
SQLでもおなじみのものなので、あまり説明することがありませんw


OrderBy及びOrderByDescendingメソッドは、単一キーでのソートを行います。
複合キーでのソートを行う場合には、次回記述するThenBy, ThenByDescendingを
組み合わせて利用します。


書式は以下のようになっています。

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
)

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IComparer<TKey> comparer
)

public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
)

public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IComparer<TKey> comparer
)


どちらも2つずつ定義されていて、片方はIComparerを受け取るようになっています。
カスタムオブジェクトを作成していて、そのComparerが存在する場合に利用します。


一点だけ、注目するべき所は、戻り値です。
通常のクエリ演算子では、IEnumerableとなっている部分がIOrderedEnumerableとなっています。
IOrderedEnumerableは、IEnumerableのカスタムインターフェースです。


戻り値がこのようになっているのは理由があって、次回取り上げるThenBy, ThenByDescendingにつなげるように
なっているためです。ThenBy, ThenByDescendingメソッドは、共にIOrderedEnumerableを引数に受け取るように
定義されています。なので、必然的にThenBy, ThenByDescendingはOrderByの後で利用しないといけないようになっています。


尚、LINQのソートは、「安定ソート (Stable Sort)」です。


以下サンプルです。

    #region LinqSamples-22
    public class LinqSamples22 : IExecutable
    {
        class Person
        {
            public int    Id   { get; set; }
            public string Name { get; set; }
                
            public override string ToString()
            {
                return string.Format("[ID={0}, NAME={1}]", Id, Name);
            }
        }
        
        public void  Execute()
        {
            var persons = new List<Person>
                          {
                              new Person{ Id = 1001, Name = "gsf_zero1" },
                              new Person{ Id = 1000, Name = "gsf_zero2" },
                              new Person{ Id = 111,  Name = "gsf_zero3" },
                              new Person{ Id = 9889, Name = "gsf_zero4" },
                              new Person{ Id = 9889, Name = "gsf_zero5" },
                              new Person{ Id = 100,  Name = "gsf_zero6" }
                          };
            
            //
            // 順序付け演算子には、以下のものが存在する。
            //
            //     ・OrderBy
            //     ・OrderByDescending
            //     ・ThenBy
            //     ・ThenByDescending
            //
            // OrderByは昇順ソート、OrderByDescendingは降順ソートを行う。どちらも単一キーにてソートを行う。
            // 複合キーにて、ソート処理を行う場合は、OrderBy及びOrderByDescendingに続いて、ThenBy及びThenByDescendingを利用する。
            //
            // OrderBy及びOrderByDescendingメソッドは、他のLINQ標準演算子と戻り値が異なっており
            //     IOrderedEnumerable<T>
            // を返す。また、ThenBy及びThenByDescendingメソッドは、引数にIOrderedEnumerable<T>を渡す必要がある。
            // なので、必然的に、ThenByはOrderByの後で呼び出さないと利用出来ない。
            //
            // LINQの並び替え処理は、安定ソート(Stable Sort)である。
            // つまり、同じキーの要素がシーケンス内に複数存在した場合、並び替えた結果は元の順番を保持している。
            //
            
            //
            // IDで昇順ソート.
            //
            var sortByIdAsc = persons.OrderBy(aPerson => aPerson.Id);
            
            Console.WriteLine("================= IDで昇順ソート =================");
            Console.WriteLine(string.Join(Environment.NewLine, sortByIdAsc));
            
            //
            // IDで降順ソート.
            //
            var sortByIdDesc = persons.OrderByDescending(aPerson => aPerson.Id);
            
            Console.WriteLine("================= IDで降順ソート =================");
            Console.WriteLine(string.Join(Environment.NewLine, sortByIdDesc));
            
            //
            // 安定ソートの確認。
            //
            var sortByIdAscAndDesc = persons.OrderByDescending(aPerson => aPerson.Id).OrderBy(aPerson => aPerson.Id);
            
            Console.WriteLine("================= 安定ソートの確認 =================");
            Console.WriteLine(string.Join(Environment.NewLine, sortByIdAscAndDesc));
        }
    }
    #endregion


実行すると以下のように出力されます。

  ================= IDで昇順ソート =================
  [ID=100, NAME=gsf_zero6]
  [ID=111, NAME=gsf_zero3]
  [ID=1000, NAME=gsf_zero2]
  [ID=1001, NAME=gsf_zero1]
  [ID=9889, NAME=gsf_zero4]
  [ID=9889, NAME=gsf_zero5]
  ================= IDで降順ソート =================
  [ID=9889, NAME=gsf_zero4]
  [ID=9889, NAME=gsf_zero5]
  [ID=1001, NAME=gsf_zero1]
  [ID=1000, NAME=gsf_zero2]
  [ID=111, NAME=gsf_zero3]
  [ID=100, NAME=gsf_zero6]
  ================= 安定ソートの確認 =================
  [ID=100, NAME=gsf_zero6]
  [ID=111, NAME=gsf_zero3]
  [ID=1000, NAME=gsf_zero2]
  [ID=1001, NAME=gsf_zero1]
  [ID=9889, NAME=gsf_zero4]
  [ID=9889, NAME=gsf_zero5]

================================
過去の記事については、以下のページからご参照下さい。