web-dev-qa-db-ja.com

IComparerを使用した並べ替え

IComparerを使用してポイントのリストを並べ替えようとしています。 IComparerクラスは次のとおりです。

public class CoordinatesBasedComparer : IComparer
{
    public int Compare(Object q, Object r)
    {
        Point a = (p)q;
        Point b = (p)r;
        if ((a.x == b.x) && (a.y == b.y))
            return 0;
        if ((a.x < b.x) || ((a.x == b.x) && (a.y < b.y)))
            return -1;

        return 1;
    }
}

クライアントコードでは、このクラスを使用してポイントのリストをソートしようとしています(タイプList<Point>):

CoordinatesBasedComparer c = new CoordinatesBasedComparer();
Points.Sort(c);

コードはエラーになります。どうやらIComparer<Point>をsortメソッドの引数として。
これを修正するにはどうすればよいですか?

34
Aadith

厳密に型のインターフェイスを実装する必要があります( [〜#〜] msdn [〜#〜] )。

_public class CoordinatesBasedComparer : IComparer<Point>
{
    public int Compare(Point a, Point b)
    {
        if ((a.x == b.x) && (a.y == b.y))
            return 0;
        if ((a.x < b.x) || ((a.x == b.x) && (a.y < b.y)))
            return -1;

        return 1;
    }
}
_

ところで、私はあなたがあまりにも多くの中括弧を使用していると思います、それらはコンパイラに貢献するときにのみ使用されるべきだと思います。これは私のバージョンです:

_if (a.x == b.x && a.y == b.y)
    return 0;
if (a.x < b.x || (a.x == b.x && a.y < b.y))
    return -1;
_

私がreturn (0)を使っている人が嫌いなように。


.Net-3.5 +アプリケーションを対象とする場合、並べ替えがより簡単で高速なLINQを使用できることに注意してください。

LINQ vesionは次のようなものです。

_var orderedList = Points.OrderBy(point => point.x)
                        .ThenBy(point => point.y)
                        .ToList();
_
44
gdoron
public class CoordinatesBasedComparer : IComparer, IComparer<Point>
{
    public int Compare(Point a, Point b)
    {
        if ((a.x == b.x) && (a.y == b.y))
            return 0;
        if ((a.x < b.x) || ((a.x == b.x) && (a.y < b.y)))
            return -1;

        return 1;
    }
    int IComparer.Compare(Object q, Object r)
    {
        return Compare((Point)q, (Point)r);            
    }
}
12
Marc Gravell

あなたが私のように遅い場合、-1と1はIComparerを使用するときに推論するのが難しい場合があります。それについて考える方法は、xが最初に行くべきときであり、-1を返します。 yが最初に必要な場合、1を返します。

並べ替えの対象となるフィールドがたくさんあると、混乱を招く可能性があります。 Enumを使用して、比較ロジックを1および-1より読みやすくしてから、結果をキャストできます。

この例では、ヌルフィールドの数が最も少ないオブジェクトを前面に配置します。

public class NullishObjectsToTheBackOfTheLine: IComparer<ClassToCompare>
{
    private enum Xy
    {
        X = -1,
        Both = 0,
        Y = 1
    };

    //the IComparer implementation wraps your readable code in an int cast.
    public int Compare(ClassToCompare x, ClassToCompare y)
    {
        return (int) CompareXy(x, y);
    }

    private static Xy CompareXy(ClassToCompare x, ClassToCompare y)
    {
        if (x == null && y == null) return Xy.Both;

        //put any nulls at the end of the list
        if (x == null) return Xy.Y;
        if (y == null) return Xy.X;

        if (x.Country == y.Country && x.ProductId == y.ProductId) return Xy.Both;

        //put the least amount of at the front
        if (x.ProductId == null && x.Country == null) return Xy.Y;
        if (y.ProductId == null && y.Country == null) return Xy.X;

        //put the country values that are not nulls in front
        if (x.Country != y.Country) return x.Country != null ? Xy.X :  Xy.Y;

        //if we got this far, one of these has a null product id and the other doesn't
        return x.ProductId != null ? Xy.X : Xy.Y;
    }

}

public class ClassToCompare
{
    public string Country { get; set; }
    public string ProductId { get; set; }
}
6
Chad Hedgcock

タイプInvalidOperationのオブジェクトをSortedList<MyClass>に追加しているときに、MyClassエラーが発生しました。間違って、IComparerインターフェイスを実装していました。実装する必要があったのは、ICompare.Compare(MyClass x、MyClass y)ではなく、CompareTo(MyClass other)メソッドを使用したIComparableでした。これは簡単な例です:

SortedList<MyClass> sortedList = new SortedList<MyClass>();
MyClass a=new MyClass(), b=new MyClass();
sortedList.Add(a);
sortedList.Add(b); // Note, sort only happens once second element is added

これにより修正されました

public class MyClass : IComparable<MyClass>
{
    int IComparable<MyClass>.CompareTo(MyClass other)
    {
        // DoCompareFunction(this, other); and return -1,0,1
    }
}

これは壊れていました(SortedList<MyClass>に追加する場合はこれをしないでください)

public class MyClass : IComparer<MyClass>
{
    int IComparable<MyClass>.Compare(MyClass x, MyClass y)
    {
        // DoCompareFunction(x, y); and return -1,0,1
    }
}

これはエラーでした:

配列内の2つの要素を比較できませんでした。
System.Collections.Generic.ArraySortHelper`1.BinarySearch(T []配列、Int32インデックス、Int32長さ、T値、IComparer`1比較子)
at System.Array.BinarySearch [T](T []配列、Int32インデックス、Int32長さ、T値、IComparer`1比較子)
System.Collections.Generic.SortedList`2.Add(TKeyキー、TValue値)

0
Jason Hitchings