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

いろいろ備忘録日記

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

Linq入門記-25 (LINQ To Object, ThenBy, ThenByDescending)

C# Linq


前回に引き続き、今回はThenByとThenByDescendingです。
説明の方は、前回で大体行っているので、今回はサンプルのみとします。


ThenByとThenByDescendingは、複合キーにてソートする際にOrderByメソッドと
組み合わせて利用します。


ThenBy及びThenByDescendingは、単独では利用できません。
常にOrderByもしくはOrderByDescendingメソッドの結果の後に利用する必要があります。


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

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

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

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

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


以下サンプルです。

    #region LinqSamples-23
    public static class StringExtensions
    {
        public static int ToInt(this string self)
        {
            int i;
            if (!int.TryParse(self, out i))
            {
                return int.MinValue;
            }
            
            return i;
        }
    }
    
    public class LinqSamples23 : 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の昇順で、且つ、Nameの数字部分の昇順でソート.
            //
            // 以下のクエリ式と同じ事となる。
            //     from    aPerson in persons
            //     orderby aPerson.Id, aPerson.Name.Last().ToString().ToInt()
            //     select  aPerson
            //
            var sortByIdAndNameAsc = persons
                                        .OrderBy(aPerson => aPerson.Id)
                                        .ThenBy(aPerson => aPerson.Name.Last().ToString().ToInt());

            Console.WriteLine("================= IDの昇順で、且つ、Nameの数字部分の昇順でソート. =================");
            Console.WriteLine(string.Join(Environment.NewLine, sortByIdAndNameAsc));
            
            //
            // IDの昇順で、且つ、Nameの数字部分の降順でソート.
            //
            // 以下のクエリ式と同じ事となる。
            //     from    aPerson in persons
            //     orderby aPerson.Id, aPerson.Name.Last().ToString().ToInt() descending
            //     select  aPerson
            //
            var sortByIdAndNameDesc = persons
                                        .OrderBy(aPerson => aPerson.Id)
                                        .ThenByDescending(aPerson => aPerson.Name.Last().ToString().ToInt());
            
            Console.WriteLine("================= IDの昇順で、且つ、Nameの数字部分の降順でソート. =================");
            Console.WriteLine(string.Join(Environment.NewLine, sortByIdAndNameDesc));
        }
    }
    #endregion


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

  ================= IDの昇順で、且つ、Nameの数字部分の昇順でソート. =================
  [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の昇順で、且つ、Nameの数字部分の降順でソート. =================
  [ID=100, NAME=gsf_zero6]
  [ID=111, NAME=gsf_zero3]
  [ID=1000, NAME=gsf_zero2]
  [ID=1001, NAME=gsf_zero1]
  [ID=9889, NAME=gsf_zero5]
  [ID=9889, NAME=gsf_zero4]

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