はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】IComparerインターフェイスを使って並べ方を変更する

はじめに

今回はC#のよく使うインターフェイスの一つであるIComparerについての記事になります。

前に取り上げたIComparableとよく一緒に取り上げられたりします。

www.hanachiru-blog.com

これらの使用用途の違いは、

  • IComparableソート方法が既に決まっているとき
  • IComparerソート方法が複数あり場合に応じて変更したいとき

に用いられるイメージです。

もっとちゃんと言うとIComparerインターフェイスは比較処理と比較される対象を分離することができるところが特徴です。

では早速みていきましょう。

IComparerインターフェイス

IComparerインターフェイスを実装することで2 つのオブジェクトを比較するメソッドを提供します。
IComparer インターフェイス (System.Collections) | Microsoft Docs


具体的に書くとIComparerインターフェイスを実装しているクラスはCompareメソッドを実装しなければなりません。

using System.Runtime.InteropServices;

[ComVisible (true)]
public interface IComparer
{
	int Compare (object x, object y);
}
public interface IComparer<in T>
{
	int Compare (T x, T y);
}

IComparerIComparer<T>には定義からみても機能的に大差ありません。

ジェネリックの方はCompareメソッドの引数が固定になりますが、むしろいろんなチェックなどを自前で実装しなくてよく楽なことが多いので、基本はジェネリックの方を使うとよいでしょう。

Compareメソッドの返り値は以下のように定義しなければなりません。

  • オブジェクトが引数で与えられたオブジェクトより前にあるなら0未満
  • オブジェクトが引数で与えられたオブジェクトと同じ位置なら0
  • オブジェクトが引数で与えられたオブジェクトより後にあるなら0より大きい

実際に使ってみる

配列を昇順・降順するサンプルを書いてみました。

Array.Sortメソッドには引数にIComparerを指定することができます。

class MainClass
{
    static void Main()
    {
        // 1~10のランダムにした配列
        var array = Enumerable.Range(1, 10).OrderBy(t => Guid.NewGuid()).ToArray();

        // 昇順のソート
        Array.Sort(array, new AscendingComparer());

        Console.WriteLine(string.Join(",", array));

        // 降順にソート
        Array.Sort(array, new DescendingComparer());

        Console.WriteLine(string.Join(",", array));
    }

    // 前の方が小さくなるようする
    public class AscendingComparer : IComparer<int>
    {
        public int Compare(int x, int y)
        {
            return x - y;
        }
    }

    // 前の方が大きくなるように
    public class DescendingComparer : IComparer<int>
    {
        public int Compare(int x, int y)
        {
            return y - x;
        }
    }
}

さいごに

これらのIComparerIComparer<T>をより良く活用するために、Comparison<T>デリゲートComparer<T>クラスComparer.Createメソッドといったものが出てきています。

特にComparer<T>クラスComparer.Createメソッドあたりは触っていた方が良い気がするので、また暇があれば記事を書こうかなと思ってます。

ではまた。