スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
Prev.    Category    Next 

C# インターフェース - IComparable, IComparable(T)

C# では覚えておくと役に立つインターフェースがいろいろとあります。 このうちの幾つかについて紹介していきたいと思います。
インターフェース 対象 使えるようになる機能
IComparable, IComparable<T> コンテナーに格納するクラス 格納したコンテナーのソート、検索など
IEnumerable コンテナークラス foreach
IEnumerable<T> LINQ の各種メソッド
IDisposable ファイルなどの後処理のタイミング管理が必要なクラス using

今回は IComparable, IComparable<T> インターフェースについての説明です。

用途

配列(Array)などのコンテナークラスでは数値を格納した場合に、 ソートや二分探索(ソート済みのデータから高速に検索)などができます。

IComparable または IComparable<T> インターフェースを継承しておけば、自作のクラスでもこれらの機能が使えるようになります。
また、 SortedList のような比較を必要とするコンテナーでは継承していないと格納することができません。

コンテナーに格納するようなクラスでは実装しておいた方がいいでしょう。

IComparable

まず IComparable から説明します。

実装するメソッド

IComparable インターフェースを継承した場合、CompareTo() メソッドを実装する必要があります。
int CompareTo(Object obj);
これは C 言語で言えば、文字列の strcmp() に相当する比較用メソッドです。
比較対象(obj)を受け取り、自身(this)と比べた結果を数値として返します。
比較 戻り値
obj < this -1 以下の整数
obj == this 0
this < obj 1 以上の整数

cs_icomparable.png

サンプル

サンプルとして点クラスを作成しました。 コンパイルする場合は以下のコマンドを実行します。
 > csc IComparableSample.cs Point_IComparable.cs
csc.exe の使用したコンパイル方法については以前の記事を見て下さい。
点クラス Point は x, y のプロパティを持たせています。
CompareTo() メソッドはまず x で比較し、 同じ場合に y で比較するという仕様にしました。

Point_IComparable.cs(抜粋) :
class Point : IComparable
{
    public int x  { get; set; }
    public int y  { get; set; }

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    /// <summary>
    ///   比較メソッド
    /// </summary>
    public int CompareTo(Object obj)
    {
        if (obj == null) return 1;

        Point other = (Point)obj;
        if (other.x == x) {
            return y - other.y;
        }       
        return x - other.x;
    }
}
作成した Point クラスを使った例は IComparableSample.cs に記述しています。
ここで、BinarySearch() の例を後にしているのは、ソートしたデータでなければ検索できないためです。

IComparableSample.cs(抜粋) :
class Program
{
    static void Main()
    {
        // Point を格納したデータを準備
        Point [] ary = {
            new Point(1, 2),
            new Point(3, 5),
            new Point(1, 9),
            new Point(4, 1),
            new Point(3, 1)
        };          
        DumpArray("Original", ary);
            
        // データのソート
        Array.Sort(ary);
        DumpArray("Sorted", ary);

        // 二分探索
        Console.WriteLine("## Binary Search ##");
        var target = new Point(3, 1);
        int pos = Array.BinarySearch(ary, target);
        Console.WriteLine("{0} @ {1}", target, pos);
    }
}
実行結果 :
## Original ##
(1, 2) (3, 5) (1, 9) (4, 1) (3, 1) 

## Sorted ##
(1, 2) (1, 9) (3, 1) (3, 5) (4, 1) 

## Binary Search ##
(3, 1) @ 2

IComparable<T>

IComparable<T> は IComparable のジェネリック版です。 どちらを使っても同じように使うことができます。

わかりやすいように先に IComparable の説明を行いましたが、 実際に使うのは ジェネリック版の IComparable<T> が良いでしょう。
CompareTo() 実装時にキャストしなくて済みますし、若干処理が速いようです。 IComparable<T> の方がいいなら、なぜ IComparable があるのかというと、 IComparable が先にできていたためです。 ジェネリックは C# 2.0 から追加されています。

実装するメソッド

IComparable<T> の場合はジェネリックな CompareTo() を実装します。
int CompareTo(T other);
cs_icomparable_t.png

サンプル

点クラスを使用する側のコードは IComparable と同じ IComparableSample.cs を使用します。
 > csc IComparableSample.cs Point_IComparable_T.cs

Point_IComparable_T.cs(抜粋) :
class Point : IComparable<Point>
{
    public int CompareTo(Point other)
    {
        if (other == null) return 1;
             
        if (other.x == x) {
            return y - other.y;
        }       
        return x - other.x;
    }   
}
実行結果も同じです。

ジェネリックな Point

ついでに Point をジェネリックにしたサンプルも紹介します。

前のサンプルは Point の x, y の型は int 固定でしたが、 double などの任意の型を仕様できるようになります。
ただし、 CompareTo() で比較する必要があるので、 完全に任意ではなく、x, y の型は IComparable を継承しているなければなりません。

クラスのジェネリックと IComparable がジェネリックかどうかは関係ありません。 サンプルでは IComparable<T> で実装していますが、 IComparable でも同じように実装できます。


サンプルは今度は 1 つのファイルに記述しています。
 > csc GenericPointSample.cs 

GenericPointSample.cs(抜粋) :
class Point<Type> : IComparable<Point<Type> >
    where Type : IComparable
{
    public Type x  { get; set; }
    public Type y  { get; set; }

    public Point(Type x, Type y)
    {
        this.x = x;
        this.y = y;
    }

    public int CompareTo(Point<Type> other)
    {
        if (other == null) return 1;
            
        if (x.CompareTo(other.x) == 0) {
            return y.CompareTo(other.y);
        }       
        return x.CompareTo(other.x);
    }

} // Point

実行結果は他のサンプルと同じです。


関連記事
スポンサーサイト
Prev.    Category    Next 

Facebook コメント


コメント

コメントの投稿

Font & Icon
非公開コメント

このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
28位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
4位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

07月 | 2017年08月 | 09月
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。