(1) C#のIComparerの実装方法や用法について
(1-1) IComparerの概要
(1-2) STEP0:比較をするクラスの定義
(1-3) STEP1:IComparerインターフェイスの実装
(1-4) STEP2:Compareメソッドの実装
(1-5) STEP3:ソートの実行
(1-6) サンプルプログラム
(1) C#のIComparerの実装方法や用法について
IComparerはオブジェクト同士の比較を行うためのメソッドを公開したインターフェイスです。
int型やdouble型などの基本データ型の比較はイメージが付きやすいが、複数のフィールドを持つクラスとなると、どのように比較するでしょうか?
結論として、オブジェクト同士の比較の場合は一致とみなす条件を自分たちで定義でき、それに合致するかどうかで、イコールかどうかを判断しています。
この記事ではIComparerの概要や使い方についてご紹介いたします。
(1-1) IComparerの概要
「IComparer」インターフェイスは主に「要素のソート」に利用されます。「2つのインスタンスの比較」を行う点は「IComparable」と似ていますが、異なる点として「IComparable」では出来ない「自身のコントロールが及ばない(=変更権限のないクラス)のインスタンス比較」にも対応する事ができます。
(1-2) STEP0:比較をするクラスの定義
事前準備としてIComparerで比較したいクラスを定義します(この手順はIComparer特有のステップではないのですが、省略すると分かりにくいので書きます)。
下記例のBig4Players2クラスでは、男子テニスの「Big4」と呼ばれている4名の名前(Name)と、グランドスラム優勝回数(GrandSlamWin)を保持するための容器です。最終的にはint型の優勝回数の「降順」(大きい順)のソートを実現します。
class Big4Players2 { // メンバ変数 public string Name { get; set; } public int GrandSlamWin { get; set; } public override string ToString() { return $"{this.Name} {this.GrandSlamWin}"; } }
(参考)
「{ get; set; }」は「プロパティ」と呼ばれ、メンバ変数のゲッター(取得)、セッター(更新)のメソッドを定義しています。
(1-3) STEP1:IComparerインターフェイスの実装
まずはIComparerインターフェイスを実装したクラスを定義します。
class [クラス名] : IComparer <[比較対象クラス名]> { //クラスの定義 }
(STEP1)
// STEP1:IComparerインターフェイスの実装 class Big4Comparer : IComparer<Big4Players2> { //クラスの実装 }
(1-4) STEP2:Compareメソッドの実装
次にCompareメソッド「public int Compare(object x, object y)」を実装します。このメソッドは同じ型の2つのインスタンスを比較し、その大小をint型で返却します。戻り値の値はソートを昇順でしたいのか?降順でしたいのか?によって次のように定義します。
(STEP2)
class Big4Comparer : IComparer<Big4Players2> { // STEP2:Compareメソッドの実装 public int Compare(Big4Players2 x, Big4Players2 y) { // 降順にソートしたいので、x < y に1を割り当て if (x.GrandSlamWin < y.GrandSlamWin) { return 1; } // 降順にソートしたいので、x > y に-1を割り当て else if (x.GrandSlamWin > y.GrandSlamWin) { return -1; } else { return 0; } } }
(1-5) STEP3:ソートの実行
ここまで来たら実際にソートしたいListを定義して、要素を追加してSort()メソッドを実行する事でソートが行えます。Sortメソッドの引数には先ほど定義したBig4Comparerクラスのインスタンスを与えます。
(STEP3)
// var(暗黙型)でBig4Players2のリストを定義 var big4 = new List(); // リストに要素を追加 big4.Add(new Big4Players2() { Name = "Roger Federer", GrandSlamWin = 20 }); big4.Add(new Big4Players2() { Name = "Rafale Nadal", GrandSlamWin = 20 }); big4.Add(new Big4Players2() { Name = "Novak Djokovic", GrandSlamWin = 17 }); big4.Add(new Big4Players2() { Name = "Andy Murray", GrandSlamWin = 3 }); // ソートの実行(内部的にCompareメソッドが使われる) big4.Sort(new Big4Comparer());
(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 { // STEP1:IComparerインターフェイスの実装 class Big4Comparer : IComparer<Big4Players2> { // STEP2:Compareメソッドの実装 public int Compare(Big4Players2 x, Big4Players2 y) { // 降順にソートしたいので、x < y に1を割り当て if (x.GrandSlamWin < y.GrandSlamWin) { return 1; } // 降順にソートしたいので、x > y に-1を割り当て else if (x.GrandSlamWin > y.GrandSlamWin) { return -1; } else { return 0; } } } class Big4Players2 { // メンバ変数 public string Name { get; set; } public int GrandSlamWin { get; set; } // コンソール出力用のメソッド public override string ToString() { return $"{this.Name} {this.GrandSlamWin}"; } } class Program2 { static void Main(string[] args) { // var(暗黙型)でBig4Players2のリストを定義 var big4 = new List<Big4Players2>(); // リストに要素を追加 big4.Add(new Big4Players2() { Name = "Roger Federer", GrandSlamWin = 20 }); big4.Add(new Big4Players2() { Name = "Rafale Nadal", GrandSlamWin = 20 }); big4.Add(new Big4Players2() { Name = "Novak Djokovic", GrandSlamWin = 17 }); big4.Add(new Big4Players2() { Name = "Andy Murray", GrandSlamWin = 3 }); // ソートの実行(内部的にCompareメソッドが使われる) big4.Sort(new Big4Comparer()); big4.ForEach(big4player => Console.WriteLine(big4player)); } } }
(図161)実行結果