(1) C#のIComparableの実装方法+IComparerとの違いについて
(1-1) IComparableの概要とIComparableとの違い
(1-2) STEP0:比較をするクラスの定義
(1-3) STEP1:IComparableインターフェイスの実装
(1-4) STEP2:Compareメソッドの実装
(1-5) STEP3:ソートの実行
(1-6) サンプルプログラム
(1) C#のIComparableの実装方法+IComparerとの違いについて
(1-1) IComparableの概要とIComparableとの違い
「IComparable」は、オブジェクト同士の比較を行うためのメソッドを公開したインターフェイスです。似た名前のインターフェイスで「IComparer」がありますが、違いとして「IComparable」は自分と同じ型のオブジェクトを受け取って比較する(自分と相手の比較)なのに対して、「IComparer」は同じ型の異なるオブジェクトを比較する(二者の比較)という点で異なります。
もう少しイメージが湧きやすいように、プログラムの骨組みで比較すると、次のようなイメージです。
(図111)IComparableは「自クラス」と同型の「相手クラス」との比較
(図112)IComparerは「2つの同型の異なるクラス」同士の比較
(1-2) STEP0:比較をするクラスの定義
まずはベースとなる、比較を行いたいクラスを作ります。
次の例は「Big4Players」という、男子テニスの「Big4」と呼ばれる選手(フェデラー、ナダル、ジョコビッチ、マレー)の「名前」(Name)と「グランドスラム優勝回数」(GrandSlamWin)と保持するためのクラスです(テニスネタでスミマセン・・💦)。
(STEP0)
// STEP0:比較をするクラスの定義 class Big4Players { // メンバ変数 public string Name { get; set; } public int GrandSlamWin { get; set; } }
(参考)
「{ get; set; }」は「プロパティ」と呼ばれ、メンバ変数のゲッター(取得)、セッター(更新)のメソッドを定義しています。
(1-3) STEP1:IComparableインターフェイスの実装
次に、定義したクラスが「IComparable」インターフェイスを実装するように改修します。
(STEP1)
// STEP0:比較をするクラスの定義 // STEP1:IComparableインターフェイスの実装 class Big4Players : IComparable<Big4Players> { // メンバ変数 public string Name { get; set; } public int GrandSlamWin { get; set; } }
(1-4) STEP2:CompareToメソッドの実装
次はいよいよ「CompareTo」メソッドを実装します。
ちなみにIComparerの時の比較メソッドは「Compare」という名前でしたが、今回は「自分」と「相手」を比較するので「CompareTo」(~と比べる)の方が確かに名前としてしっくり来ます。
今回は優勝回数が多い順に並べるので降順ソートで実装しています。
(STEP2)
// STEP0:比較をするクラスの定義 // STEP1:IComparableインターフェイスの実装 class Big4Players : IComparable { // メンバ変数 public string Name { get; set; } public int GrandSlamWin { get; set; } // STEP2:CompareToメソッドの実装 public int CompareTo(Big4Players other) { // 降順にソートしたいので、this(自分) < other(相手) に1を割り当て if (this.GrandSlamWin < other.GrandSlamWin) { return 1; } // 降順にソートしたいので、this(自分) > other(相手) に-1を割り当て else if (this.GrandSlamWin > other.GrandSlamWin) { return -1; } else { return 0; } } // コンソール出力用のメソッド public override string ToString() { return $"{this.Name} {this.GrandSlamWin}"; } }
(1-5) STEP3:ソートの実行
ここまで来たら実際にソートしたいListを定義して、要素を追加してSort()メソッドを実行する事でソートが行えます。Sortメソッドの引数には先ほど定義したBig4Comparerクラスのインスタンスを与えます。
class Program { static void Main(string[] args) { // var(暗黙型)でBig4Players2のリストを定義 var big4 = new List<Big4Players>(); // リストに要素を追加 big4.Add(new Big4Players() { Name = "Roger Federer", GrandSlamWin = 20 }); big4.Add(new Big4Players() { Name = "Rafale Nadal", GrandSlamWin = 20 }); big4.Add(new Big4Players() { Name = "Novak Djokovic", GrandSlamWin = 17 }); big4.Add(new Big4Players() { Name = "Andy Murray", GrandSlamWin = 3 }); // ソートの実行(内部的にCompareToメソッドが使われる) big4.Sort(); // コンソール出力 big4.ForEach(big4player => Console.WriteLine(big4player)); } }
(1-6) サンプルプログラム
上記STEP0~STEP3までを繋げて、main文などを追記して実行可能にしたものを掲載します。
プログラム中で登場するvar(暗黙型)については別記事でも説明しているため、興味ある方は併せてご覧いただけたらと思います。
参考①:C#のvarの使いどころは?初めての方に向けてサンプルプログラムを使ってご紹介
参考②:C#のvarとは?型を調べる方法や制約事項についてもご紹介
(サンプルプログラム)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IComparerTest { // STEP0:比較をするクラスの定義 // STEP1:IComparableインターフェイスの実装 class Big4Players : IComparable<Big4Players> { // メンバ変数 public string Name { get; set; } public int GrandSlamWin { get; set; } // STEP2:CompareToメソッドの実装 public int CompareTo(Big4Players other) { // 降順にソートしたいので、this(自分) < other(相手) に1を割り当て if (this.GrandSlamWin < other.GrandSlamWin) { return 1; } // 降順にソートしたいので、this(自分) > other(相手) に-1を割り当て else if (this.GrandSlamWin > other.GrandSlamWin) { return -1; } else { return 0; } } // コンソール出力用のメソッド public override string ToString() { return $"{this.Name} {this.GrandSlamWin}"; } } class Program { static void Main(string[] args) { // var(暗黙型)でBig4Players2のリストを定義 var big4 = new List<Big4Players>(); // リストに要素を追加 big4.Add(new Big4Players() { Name = "Roger Federer", GrandSlamWin = 20 }); big4.Add(new Big4Players() { Name = "Rafale Nadal", GrandSlamWin = 20 }); big4.Add(new Big4Players() { Name = "Novak Djokovic", GrandSlamWin = 17 }); big4.Add(new Big4Players() { Name = "Andy Murray", GrandSlamWin = 3 }); // ソートの実行(内部的にCompareToメソッドが使われる) big4.Sort(); // コンソール出力 big4.ForEach(big4player => Console.WriteLine(big4player)); } } }
(図161)実行結果
狙った通り降順にソートされています(20⇒20⇒17⇒3)