这更像是一个'你能解释这个'的问题而不是其他任何问题。
我在工作中遇到了一个问题,我们在表中使用NaN值,但是当表被排序时,它以一种非常奇怪,奇怪的方式出现。我认为NaN正在捣乱,所以我写了一个测试应用程序来判断这是否属实。这就是我所做的。
static void Main(string[] args)
{
double[] someArray = { 4.0, 2.0, double.NaN, 1.0, 5.0, 3.0, double.NaN, 10.0, 9.0, 8.0 };
foreach (double db in someArray)
{
Console.WriteLine(db);
}
Array.Sort(someArray);
Console.WriteLine("\n\n");
foreach (double db in someArray)
{
Console.WriteLine(db);
}
Console.ReadLine();
}
结果如下:
在:
4,2,NaN,1,5,3,NaN,10,9,8
后:
1,4,NaN,2,3,5,8,9,10,NaN
所以是的,NaN有些如何使排序的数组以奇怪的方式排序。
引用弗莱; “为什么这些东西?”
答案 0 :(得分:10)
我相信那是因为
a < NaN == false
a > NaN == false
a == NaN == false
因此对它们的比较会中断,这会导致整个排序。
答案 1 :(得分:6)
请参阅错误报告Bug in List<double/single>.Sort() [.NET35] in list which contains double.NaN,然后在Why does .NET 4.0 sort this array differently than .NET 3.5?上向Hans Passant投票,我从中撕开链接。
[请参阅帖子:Why does .NET 4.0 sort this array differently than .NET 3.5?,希望有关此特定问题的更有用的讨论可以在实际中找到。我也在那里交叉发布了这个回复。]
Phil在.NET4中指出的行为是在CompareTo中定义的。有关.NET4,请参阅double.CompareTo。这与.NET35中的行为相同,但应该在两个版本中都是一致的,根据方法文档......
Array.Sort(double[])
:似乎没有按预期使用CompareTo(double[])
,这很可能是一个错误 - 请注意Array.Sort(object [])和Array之间的区别.Sort(双[])低于。我希望对以下内容进行澄清/更正。
在任何情况下,使用>
和<
以及==
的答案都解释了为什么这些运算符不起作用但无法解释< / strong>为什么Array.Sort
导致意外输出。以下是我的一些调查结果,尽管它们可能很少。
首先,double.CompareTo(T)
方法文档 - 根据文档明确定义了此排序:
小于零: 此实例小于值。 -要么- 此实例不是数字(NaN),值是数字。
零: 此实例等于值。 -要么- 此实例和值都不是数字(NaN),PositiveInfinity或NegativeInfinity。
大于零: 此实例大于值。 -要么- 此实例是数字,值不是数字(NaN)。
在LINQPad中(3.5和4,两者都有相同的结果):
0d.CompareTo(0d).Dump(); // 0
double.NaN.CompareTo(0d).Dump(); // -1
double.NaN.CompareTo(double.NaN).Dump(); // 0
0d.CompareTo(double.NaN).Dump(); // 1
使用CompareTo(object)
会产生相同的结果:
0d.CompareTo((object)0d).Dump(); // 0
double.NaN.CompareTo((object)0d).Dump(); // -1
double.NaN.CompareTo((object)double.NaN).Dump(); // 0
0d.CompareTo((object)double.NaN).Dump(); // 1
所以这不是问题。
现在,从Array.Sort(object[])
文档 - 开始,>
,<
或==
没有用(根据文档) - 只是CompareTo(object)
。
使用数组中每个元素的
IComparable
实现对整个一维数组中的元素进行排序。
同样,Array.Sort(T[])
使用CompareTo(T)
。
使用Array的每个元素的IComparable(Of T)泛型接口实现对整个Array中的元素进行排序。
让我们看看:
LINQPad(4):
var ar = new double[] {double.NaN, 0, 1, double.NaN};
Array.Sort(ar);
ar.Dump();
// NaN, NaN, 0, 1
LINQPad(3.5):
var ar = new double[] {double.NaN, 0, 1, double.NaN};
Array.Sort(ar);
ar.Dump();
// NaN, 0, NaN, 1
LINQPad(3.5) - 注意阵列是对象,并且CompareTo
合约的行为是“预期的”。
var ar = new object[] {double.NaN, 0d, 1d, double.NaN};
Array.Sort(ar);
ar.Dump();
// NaN, NaN, 0, 1
嗯。真。总之:
我没有想法。
快乐的编码。
答案 2 :(得分:1)
从概念上讲,NaN不是数字,因此与数字相比毫无意义,因此:
a < NaN = false for all a,
a > NaN = false for all a and
NaN != NaN (!)
要解决此问题,您需要编写自己的比较器,使用IsNaN使NaN小于(或大于)所有数字,以便它们全部出现在排序的一端。
编辑:以下是比较版本的示例:
class Program
{
private static int NaNComparison(double first, double second)
{
if (double.IsNaN(first))
{
if (double.IsNaN(second)) // Throws an argument exception if we don't handle both being NaN
return 0;
else
return -1;
}
if (double.IsNaN(second))
return 1;
if (first == second)
return 0;
return first < second ? -1 : 1;
}
static void Main(string[] args)
{
var doubles = new[] { double.NaN, 2.0, 3.0, 1.0, double.NaN };
Array.Sort(doubles, NaNComparison);
}
}
答案 3 :(得分:0)
实际上,奇怪的排序行为是.NET 3.5中的一个错误的结果。这个bug是用.NET 4.0解决的。
解决它的唯一方法是使用自己的自定义比较器,或升级到.NET 4.0。见Why does .NET 4.0 sort this array differently than .NET 3.5?
答案 4 :(得分:-1)
因为您使用的是默认排序,即QuickSort算法;实现执行不稳定的排序;也就是说,如果两个元素相等,则可能不会保留它们的顺序