いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-035 (System.IComparable)(オブジェクトの比較, CompareTo, List.Sort, ソート)


IComparableインターフェースは、System名前空間に定義されている基本インターフェースです。
このインターフェースを、実装することでオブジェクトに対して、比較機能を追加することができます。


自分でクラスを定義し、このインターフェースを実装することで、List等のコレクションにて

xxList.Sort();

で、ソートされるようになります。
オブジェクト自身に比較機能が存在しない場合は、各オブジェクトの参照にて比較が行われます。


IComparableには、CompareToメソッドが一つだけ定義されています。
このメソッドの戻り値は、intなのですが、これは他の言語でもおなじみの以下の形式で
結果を返します。

  • 小さい場合は、0より小さい値
  • 同じ場合は、0
  • 大きい場合は、0より大きい値


サンプルの方では、分かりやすいように列挙型を定義して
それを利用しています。


以下、サンプルです。

    #region IComparableSamples-01
    public class IComparableSamples01 : IExecutable
    {
        enum CompareResult : int
        {
            SMALL = -1,
            EQUAL = 0,
            BIG   = 1
        }
        
        class Person : IComparable<Person>
        {
            public int    Id   { get; set; }
            public string Name { get; set; }
                
            public int CompareTo(Person other)
            {
                if (other == null)
                {
                    return (int) CompareResult.SMALL;
                }
                
                int result  = (int) CompareResult.SMALL;
                int otherId = other.Id;
                
                if (Id == otherId)
                {
                    result = (int) CompareResult.EQUAL;
                }
                else if (Id > otherId)
                {
                    result = (int) CompareResult.BIG;
                }
                
                return result;
            }
            
            public override string ToString()
            {
                return string.Format("[ID={0}, NAME={1}]", Id, Name);
            }
        }
        
        public void Execute()
        {
            //
            // IComparableインターフェースは、インスタンスの並び替えをサポートするためのインターフェースである。
            //
            // このインターフェースを実装することで、クラスに対して順序の比較機能を付与することが出来る。
            // (List.Sortなどのソート処理時に、独自のソートルールを適用することができるようになる。)
            //  (ただし、DictionaryやHashTableなどには適用できない。これらの場合は、IEqualityComparableを実装する。)
            //
            var person1 = new Person { Id = 1, Name = "gsf_zero1" };
            var person2 = new Person { Id = 2, Name = "gsf_zero2" };
            var person3 = new Person { Id = 3, Name = "gsf_zero3" };
            var person4 = new Person { Id = 4, Name = "gsf_zero1" };
            
            var persons = new List<Person>{ person1, person2, person3, person4 };
            var random  = new Random();
            
            //
            // オブジェクト同士の比較.
            //
            for (int i = 0; i < 15; i++)
            {
                int index1 = random.Next(persons.Count);
                int index2 = random.Next(persons.Count);
                
                var p1 = persons[index1];
                var p2 = persons[index2];
                
                Console.WriteLine("person{0} CompareTo person{1} = {2}", index1, index2, (CompareResult) p1.CompareTo(p2));
            }
            
            //
            // リストのソート.
            //
            var persons2 = new List<Person>{ person3, person2, person4, person1 };
            
            // ソートせず、そのまま出力.
            Console.WriteLine("\n============== ソートせずそのまま出力. ================");
            persons2.ForEach(Console.WriteLine);
            
            // ソートを行ってから、出力.
            Console.WriteLine("\n============== ソートしてから出力. ================");
            persons2.Sort();
            persons2.ForEach(Console.WriteLine);
        }
    }
    #endregion


上記のサンプルでは、ランダムに15回リストから2つを取り出して、比較しています。
結果は、以下のようになります。

  person1 CompareTo person1 = EQUAL
  person1 CompareTo person3 = SMALL
  person1 CompareTo person2 = SMALL
  person2 CompareTo person0 = BIG
  person2 CompareTo person1 = BIG
  person3 CompareTo person0 = BIG
  person3 CompareTo person3 = EQUAL
  person1 CompareTo person2 = SMALL
  person1 CompareTo person1 = EQUAL
  person3 CompareTo person3 = EQUAL
  person0 CompareTo person2 = SMALL
  person1 CompareTo person3 = SMALL
  person2 CompareTo person1 = BIG
  person3 CompareTo person3 = EQUAL
  person0 CompareTo person3 = SMALL
  
  ============== ソートせずそのまま出力. ================
  [ID=3, NAME=gsf_zero3]
  [ID=2, NAME=gsf_zero2]
  [ID=4, NAME=gsf_zero1]
  [ID=1, NAME=gsf_zero1]
  
  ============== ソートしてから出力. ================
  [ID=1, NAME=gsf_zero1]
  [ID=2, NAME=gsf_zero2]
  [ID=3, NAME=gsf_zero3]
  [ID=4, NAME=gsf_zero1]


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

サンプルコードは、以下の場所で公開しています。