2016-06-15 34 views
1

我有一个类,为什么我的OrderBy使用这个比较器永远运行?

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运行

arr.OrderBy(i => i, new NullsAreLast()) 

与至少两个null值运行永远!任何想法为什么?

+7

您的排序并不稳定 - 如果什么都为null?那应该返回0. –

+0

什么是'arr'? –

+0

@ DanielA.White仍然不应该“永远”运行。只要它在x或y中遇到空值,它应该立即返回。我猜''arr'是一些延迟的查询,在场景后面做了一些时髦的东西 –

回答

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)))); 
+0

这个减号很好。它处理整数的所有三个条件。问题来得更早(请参阅我的答案)。 –

+0

@JoelCoehoorn很好的回答,我今天学到了一些新东西。 – JosephStyons

3

保持记住排序算法可以在排序整个序列的过程中将相同的两个值进行几次比较。因此,了解所有三种可能的结果非常重要:小于,大于和等于。

这对您的整数比较(减法操作)来说(主要)很好。在处理浮点数而不是整数时会出现一些奇怪/罕见的情况,无论如何调用.CompareTo()都是首选的做法,但在这种情况下,减法通常是足够好的。但是,这里的null检查是一个真正的问题。

想想列表几乎完成排序会发生什么。你有两个null值都已经到达列表的前面;算法只需要验证它们处于正确的位置。因为xy都是null,所以你的函数应该返回0。它们是相同的(至少为此目的)。代码总是返回-1。该值将始终小于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); 
    } 
} 
相关问题