C#ソート比較

12950 ワード

C#が同等性比較仕様を定義したのと同様に、C#もソート比較仕様を定義し、あるオブジェクトと別のオブジェクトの優先順位を決定します.ソート仕様は次のとおりです.
  • IComparableインタフェース(IComparableインタフェースおよびIComparableインタフェースを含む)
  • >および<演算子
  • ソートアルゴリズムを実装する必要がある場合は、IComparableインタフェースを使用します.次の例では、Array.Sort静的メソッドはSystemのため呼び出すことができる.StringクラスはIComparableインタフェースを実現した.
    string[] colors={"Green", "Red", "Blue"};
    Array.Sort(colors)
    foreach(string c in colors)
        Console.Write(c+ " ");
    <和>演算子は、数値タイプの比較に一般的に使用されるため、特殊です.演算子より大きいか小さいかは静的に解析されるため、複雑な計算のシーンに適用される効率的なコードを「生成」します.
    .NET Frameworkには、プラグイン式のソートプロトコルであるIComparerインタフェースも用意されています.IComparableインタフェースとIComparerインタフェースの違いは、IEquatableインタフェースとIEqualityComparerインタフェースと似ています(IEquableインタフェースとIEqualityComparerインタフェースについては、C#等化:http://www.cnblogs.com/yang_sy/p/3582946.htmlを参照してください).
     
    1.IComparableインタフェース
    IComparableインタフェースの定義は次のとおりです.
    public interface IComparable
    
        int CompareTo(Object obj);
    }
    
    public interface IComparable<in T>
    {
        int CompareTo(T other);
    }
    この2つのインタフェースは、同じ機能を定義します.値タイプの場合、IComparableインタフェースの効率はICompareインタフェースよりも高い.上の2つのインタフェースのCompareToメソッドは、次のように実行されます.
  • aがbの後ろに並んでいる場合、a.CompareTo(b)は1
  • を返す.
  • aと異なる場合は、0
  • を返します.
  • aが前に並んでいない場合は-1
  • に戻る.
    次のコードの例を見てみましょう.
    IList<Staff> staffs = new List<Staff> 
    {
        new Staff{FirstName="AAA", Title="Manager", Dept="Sale"},  
        new Staff{FirstName="BBB", Title="Accountant", Dept="Finance"},
        new Staff{FirstName="CCC", Title="Accountant", Dept="Finance"},
    };
    
    Console.WriteLine("BBB".CompareTo(staffs[0].FirstName)); // 1
    Console.WriteLine("BBB".CompareTo(staffs[1].FirstName)); // 0
    Console.WriteLine("BBB".CompareTo(staffs[2].FirstName)); // -1
    C#のほとんどの基本タイプは、IComparableインタフェースとIComparableインタフェースを実現しています.多くのカスタムタイプも同様にインタフェースを実装しており、ソートが容易です.
    IComarableとEquals
    Equalsメソッドを書き換え、IComparableインタフェースを実装したタイプを仮定します.では、Equalsがtrueを返すと、CompareToは0を返すことを望んでいます.Equalsがfalseを返すと、CompareToは任意の値を返すことができます.
    言い換えれば、等化性は対比性よりも厳しい.逆はできない.したがって、CompareToが「2つのオブジェクトが等しい」と言うと、Equalsは「この2つのオブジェクトが必ずしも等しいとは限らない」と言います.良い例はシステムですStringクラス.String.Equalsメソッドと==演算子は、シーケンス番号ソート規則を使用して文字列を比較します.つまり、各文字のUnicodeの値でソートします.StringCompareToメソッドは,それほど厳密ではない文化領域(culture-dependent)に基づいて比較する.ほとんどのコンピュータでは、文字ǖとṻ,EqualsはFalseを返し,CompareToは0を返す.
    IComparerインタフェースを介して、特定のソートアルゴリズムを完了することができます.カスタムIComparerインタフェースの実装は,CompareToとEqualsメソッドの違いをさらに増大させた.例えば、大文字と小文字を区別しない文字列比較器は、Aとaに対して0を返す.これも裏から証明されていますが、ComparToの方法はEqualsの方法ほど厳しくありません.
     
    2.<および>演算子
    <和>演算子を定義するタイプがあります.たとえば、次のようになります.
    bool after2010 = DateTime.Now > new DateTime(2010, 1, 1);
    Console.WriteLine(after2010);
    <和>演算子を実装した後、<和>演算子がIComparableインタフェースと一致することを保証する必要があります.これも.NET Frameworkの標準.
    同様に、<和>演算子が1つのタイプに再ロードされると、IComparableインタフェースの実装も要求され、逆に必要とされない.実際、ほとんどはNETタイプはIComparableインタフェースを実装し、<和>演算子は再ロードされません.これは、同等性の比較とは異なります.
  • 等しい比較を実現する場合、Equalsメソッドが再ロードされた場合、一般的には==演算子
  • が再ロードされる.
  • で並べ替え比較を行う場合、CompareToメソッドが実装されている場合、<演算子および>演算子
  • の再ロードは一般的に要求されない.
    一般に、<演算子および>演算子を再ロードする必要があるのは、次の場合のみです.
  • のタイプ自体は、このような概念
  • より大きいおよび小さいを含む.
  • 前後順比較を実行する方法は唯一の
  • である.
  • 結果は、文化的領域(Cultures)の変化に伴って変化しない
  • .
    System.Stirngタイプは最後の1つを満たしていないため、stringは>アクションおよび<アクションをサポートしません.したがって「beck」>「Anne」では、コンパイル時にエラーが投げ出されます.
     
    3.IComparableインタフェースの実装
    次のインスタンスコードでは、構造Noteは、IComparableインタフェースを実装し、<演算子と>演算子を再ロードする音楽の注釈を表します.インスタンスの完全性のためにEqualsとGetHashCodeメソッドも書き換え,==と!演算子、この例では、ソート比較を全面的に理解することができます.
    internal struct Note : IComparable, IComparable<Note>, IEquatable<Note>
    {
    
        private int semitonesFromA;
        public int SemitonesFromA
        {
            get { return semitonesFromA; }
        }
    
        public Note(int semitonesFromA)
        {
            this.semitonesFromA = semitonesFromA;
        }
    
        // generic IComparable<T>
        public int CompareTo(Note other)
        {
            if (Equals(other))
                return 0;
            return SemitonesFromA.CompareTo(other.SemitonesFromA);
        }
    
        // non-generic IComaparable
        public int IComparable.CompareTo(object other)
        {
            if (!(other is Note))
                throw new InvalidOperationException("CompareTo: Not a note");
            return CompareTo((Note)other);
        }
    
        public static bool operator <(Note n1, Note n2)
        {
            return n1.CompareTo(n2) < 0;
        }
    
        public static bool operator >(Note n1, Note n2)
        {
            return n1.CompareTo(n2) > 0;
        }
    
        // for IEquatable
        public bool Equals(Note other)
        {
            return this.SemitonesFromA == other.SemitonesFromA;
        }
    
        // override Object.Equals
        public override bool Equals(object other)
        {
            if (!(other is Note))
                throw new InvalidOperationException("CompareTo: Not a note");
            return Equals((Note)other);
        }
    
        public override int GetHashCode()
        {
            return SemitonesFromA.GetHashCode();
        }
    
        public static bool operator ==(Note n1, Note n2)
        {
            return n1.Equals(n2);
        }
    
        public static bool operator !=(Note n1, Note n2)
        {
            return !(n1 == n2);
        }
    }