Sortいろいろ IComparableでCompareToを実装するとか - C#

例えばint配列ならソートするのは簡単だ。ただ、実際にはそんな簡単モノばかりを扱うわけではない。
あるクラスを作成して、そのクラスの持つ特定のプロパティによってソートしたい場合はどうすれば良いか。
それにはIComparableインターフェイスを継承し、IComparableのメンバであるCompareToメソッドを追加し、比較処理をカスタマイズする。

例えば、以下のようなクラスがあるとする。

class Item : IComparable
{
    string _name;
    int _price;

    public Item()
    {
        _name = "";
        _price = 0;
    }
    public Item(string name, int price)
    {
        _name = name;
        _price = price;
    }

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    public int Price
    {
        get { return _price; }
        set { _price = value; }
    }

    public int CompareTo(object obj)
    {
        return this.Price - ((Item)obj).Price;
    }
}

SortメソッドはこのCompareToメソッドの比較処理によってソートされる。
public static void Main(string[] args)
{
    Item[] items = {
        new Item("foo1",1478),
        new Item("foo2",5334),
        new Item("foo3",826),
    };
    
    //ソート前のItemを表示する
    foreach (Item item in items)
    {
        Console.WriteLine("Name = {0} : Price ={1}", item.Name, item.Price);
    }

    //ソートする
    Array.Sort(items);

    Console.WriteLine("ソート後");
    //ソート後のItemを表示する
    foreach (Item item in items)
    {
        Console.WriteLine("Name = {0} : Price ={1}", item.Name, item.Price);
    }
    Console.ReadLine();
}


異なる値を比較対象にしてソートする

何で比較するか決まっていればこれで良いのだが、より柔軟に、比較処理を変更させるには?

こんなクラスがあるとして
class Cell : IComparable
{
    int _x;
    int _y;
    public Cell(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
    public int X
    {
        get { return _x; }
        set { _x = value; }
    }
    public int Y
    {
        get { return _y; }
        set { _y = value; }
    }

    public int CompareTo(object obj)
    {
        Cell cell = obj as Cell;
        return this.X - cell.X;
    }
}
このクラスをSortメソッドでソートするとXプロパティの値によって比較されソートされる。

Yプロパティの値でソートするにはどうするか。

Arrayクラスには比較処理に使用するメソッドを渡してやることが出来る。
この渡されたメソッドによって比較されソートされる。
static void Main(string[] args)
{
    Cell[] cells = {
            new Cell(91,5),
            new Cell(26,58),
            new Cell(33,34)
    };

    Array.Sort(cells, CellCompareToY);

    foreach (Cell cell in cells)
    {
        Console.WriteLine("X = " + cell.X + " , Y = " + cell.Y);
    }
}

static int CellCompareToX(Cell x, Cell y)
{
    return x.X - y.X;
}

static int CellCompareToY(Cell x, Cell y)
{
    return x.Y - y.Y;
}
「CellCompareToX」と「CellCompareToY」を用意してどちらかを渡してやることによって切り替え可能になる。

Sortを行っている箇所
Array.Sort(cells, CellCompareToY);
この部分を以下のようにしても分かりやすいかも
Array.Sort(cells, (Cell x, Cell y) => x.Y - y.Y);

Listクラスで同様のSortを行う

Listクラスでも同様に比較するメソッドを引数に渡してやることができる。
static void Main(string[] args)
{
    List<Cell> cells = new List<Cell>();

    cells.Add(new Cell(56, 93));
    cells.Add(new Cell(9, 17));
    cells.Add(new Cell(57, 11));

    cells.Sort(CompareY); //メソッドは省略
    cells.Sort((Cell x, Cell y) => x.Y - y.Y); //lambda

    foreach (Cell cell in cells)
    {
        Console.WriteLine(cell.X + " - " + cell.Y); 
    }
    Console.ReadLine();
}

0 Comments:

Recent Posts