使用IComparer进行排序

Aad*_*mia 40 c# sorting icomparer

我正在尝试使用a 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在客户端代码中,我试图使用这个类来排序点p(类型List<Point>)的列表:

CoordinatesBasedComparer c = new CoordinatesBasedComparer();
Points.Sort(c);
Run Code Online (Sandbox Code Playgroud)

代码出错了.显然它正在期待IComparer<Point>排序方法的论据.
我需要做些什么来解决这个问题?

gdo*_*ica 49

您需要实现强类型接口(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;
    }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我认为你使用了太多括号,我相信只有当它们对编译器有所贡献时才应该使用它们.这是我的版本:

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;
Run Code Online (Sandbox Code Playgroud)

就像我不喜欢用人一样return (0).


请注意,如果您定位.Net-3.5 +应用程序,则可以使用LINQ,这样可以更轻松,更快速地进行排序.

LINQ vesion可以是这样的:

var orderedList = Points.OrderBy(point => point.x)
                        .ThenBy(point => point.y)
                        .ToList();
Run Code Online (Sandbox Code Playgroud)

  • &gt;顺便说一句,我认为你使用了太多大括号,我相信只有当它们对编译器有贡献时才应该使用它们。大括号有助于避免错误。https://www.imperialviolet.org/2014/02/22/applebug.html (3认同)

Mar*_*ell 12

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);            
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @zmbq a:因为在编写比较器时,你不知道*调用者是谁,他们需要什么.并且b:因为它是1行实际代码,加上方法签名 (4认同)
  • 如果所有OP需求都是通用版本,那么在这里实现IComparer(非通用版本)有什么意义呢? (2认同)

Cha*_*ock 8

如果你像我一样慢,-1和1在使用时可能很难推理IComparer.考虑它的方法是什么时候x应该先行,返回-1.什么时候y应该先去,返回1.

如果你有很多字段需要排序,它仍然会让人感到困惑.您可以使用a 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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 没有错,这与“当 x 应该先走时,返回 -1”是一样的。当 y 应该先走时,返回 1。” (2认同)