我有一个班级,
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(y == null)
return -1;
else if(x == null)
return 1;
else
return (int)x - (int)y;
}
}
对于它应该如何工作是不言自明的。
每当我跑
arr.OrderBy(i => i, new NullsAreLast())
在null
中至少有两个arr
值,它会永远运行!知道为什么吗?
答案 0 :(得分:3)
请记住,排序算法可能会在整个序列的排序过程中多次比较相同的两个值。因此,了解所有三种可能的结果非常重要:小于,大于和等于。
这对于(结束时)整数比较(大多数)来说是很好的(减法运算)。使用浮点数而不是整数时,有一些奇怪/罕见的边缘情况,并且无论如何调用.CompareTo()
是首选做法,但在这种情况下减法通常是足够好的。但是,这里的null
检查是一个真正的问题。
考虑一下列表几乎完成排序会发生什么。您有两个null
值,它们都已经到达列表的前面;算法只需要验证它们是否处于正确的位置。由于x
和y
都是null
,因此您的函数应返回0
。它们是等价的(至少为此目的)。相反,代码始终返回-1
。 y
值始终小于x
值,因此算法始终认为它仍然需要交换它们。它交换,并试图再次做同样的事情。然后再次。然后再次。然后再次。它永远无法完成。
请改为尝试:
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(!y.HasValue)
{
if (!x.HasValue) return 0;
return -1;
}
if(!x.HasValue) return 1;
return x.Value.CompareTo(y.Value);
}
}
答案 1 :(得分:0)
比较方法结束时的减号操作不适合进行比较。你需要处理三种可能性 - x更大,y更大,或者它们是相同的。
<强> MSDN 强>
比较两个对象并返回一个值,指示是否有一个 小于,等于或大于另一个。
使用此代码,假设X为1000,Y为15.您的结果将是985,这在这里没有意义。
鉴于你的代码和方法名称,我猜你的意思是:
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(y == null)
return -1;
else if(x == null)
return 1;
else{
int diff = x - y;
if (diff == 0) return 0; //same
if (diff < 0) return 1; //y was bigger
if (diff > 0) return -1; //x was bigger
}
}
}
你甚至可以把它粉碎成一个可怕的单行:
return (y==null?-1:(x==null?1:(x-y==0?0:(x-y<0?1:-1))));