C# 使用 IComparer 进行排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14336416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using IComparer for sorting
提问by Aadith Ramia
I am trying to use an IComparer
to sort a list of Points. Here is the IComparer class:
我正在尝试使用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;
}
}
In the client code, I am trying to using this class for sorting a list of points p (of type List<Point>
):
在客户端代码中,我尝试使用此类对点 p(类型List<Point>
)列表进行排序:
CoordinatesBasedComparer c = new CoordinatesBasedComparer();
Points.Sort(c);
The code errors out. Apparently it is expecting IComparer<Point>
as argument to sort method.
What do I need to do to fix this?
代码出错了。显然它期望IComparer<Point>
作为排序方法的参数。
我需要做什么来解决这个问题?
采纳答案by gdoron is supporting Monica
You need to implement the strongly type interface (MSDN).
您需要实现强类型接口 ( 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;
}
}
BTW, I think you use too many braces, I believe they should be used only when they contribute to the compiler. This is my version:
顺便说一句,我认为您使用了太多大括号,我相信只有在它们对编译器有贡献时才应该使用它们。这是我的版本:
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;
Just like I dislike people using return (0)
.
就像我不喜欢人们使用return (0)
.
Note that if you target a .Net-3.5+ application you can use LINQ which is easier and even faster with sorting.
请注意,如果您的目标是 .Net-3.5+ 应用程序,您可以使用 LINQ,它在排序时更容易,甚至更快。
LINQ vesion can be something like:
LINQ 版本可以是这样的:
var orderedList = Points.OrderBy(point => point.x)
.ThenBy(point => point.y)
.ToList();
回答by Marc Gravell
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);
}
}
回答by Jason Hitchings
I was getting an InvalidOperation
error while adding an object of type MyClass
to a SortedList<MyClass>
. I was, incorrectly, implementing the IComparer interface. What I needed to implement was IComparable with the method CompareTo(MyClass other), instead of the ICompare.Compare(MyClass x, MyClass y). This is a simplified example:
我得到了一个InvalidOperation
错误,同时增加类型的对象MyClass
的SortedList<MyClass>
。我错误地实现了 IComparer 接口。我需要实现的是 IComparable 与方法 CompareTo(MyClass other),而不是 ICompare.Compare(MyClass x, MyClass y)。这是一个简化的例子:
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
This fixed it:
这修复了它:
public class MyClass : IComparable<MyClass>
{
int IComparable<MyClass>.CompareTo(MyClass other)
{
// DoCompareFunction(this, other); and return -1,0,1
}
}
This was broken (don't do this if adding to SortedList<MyClass>
):
这被破坏了(如果添加到,请不要这样做SortedList<MyClass>
):
public class MyClass : IComparer<MyClass>
{
int IComparable<MyClass>.Compare(MyClass x, MyClass y)
{
// DoCompareFunction(x, y); and return -1,0,1
}
}
This was the error:
这是错误:
Failed to compare two elements in the array.
at System.Collections.Generic.ArraySortHelper`1.BinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
at System.Array.BinarySearch[T](T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
at System.Collections.Generic.SortedList`2.Add(TKey key, TValue value)
无法比较数组中的两个元素。
在 System.Collections.Generic.ArraySortHelper`1.BinarySearch(T[] 数组,Int32 索引,Int32 长度,T 值,IComparer`1 比较器)
在 System.Array.BinarySearch[T](T[] 数组,Int32 索引, Int32 长度,T 值,IComparer`1 比较器)
在 System.Collections.Generic.SortedList`2.Add(TKey 键,TValue 值)
回答by Chad Hedgcock
If you're slow like me, the -1 and 1 can be difficult to reason about when using IComparer
. The way to think about it is when x
should go first, return -1. When y
should go first, return 1.
如果你像我一样慢,那么 -1 和 1 在使用IComparer
. 考虑的方法是什么时候x
应该先走,返回-1。什么时候y
应该先走,返回 1。
It can still get confusing if you have lots of fields to sort by. You can use an Enum
to make your comparison logic more readable than 1 and -1, then cast the result.
如果您有很多要排序的字段,它仍然会让人感到困惑。您可以使用 anEnum
使比较逻辑比 1 和 -1 更具可读性,然后转换结果。
This example puts objects with the least amount of null fields in the front.
此示例将具有最少空字段的对象放在前面。
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; }
}