【发布时间】:2013-12-03 23:25:52
【问题描述】:
采用自定义 IComparer,如果两个双精度数的差小于给定的 epsilon,则将它们视为相等。
如果在 OrderBy().ThenBy() 子句中使用此 IComparer 会发生什么?
具体来说,我正在考虑以下实现:
public class EpsilonComparer : IComparer<double>
{
private readonly double epsilon;
public EpsilonComparer(double epsilon)
{
this.epsilon = epsilon;
}
public int Compare(double d1, double d2)
{
if (Math.Abs(d1-d2)<=epsilon) return 0;
return d1.CompareTo(d2);
}
}
现在这个 IComparer 关系显然不是传递的。 (if a ~ b and b ~ c then a ~ c)
使用 epsilon== 0.6 :
- 比较(1, 1.5) == 0
- 比较(1.5, 2) == 0
还 - 比较(1, 2 ) == -1
如果在 OrderBy 查询中使用此 IComparer 会发生什么情况,如下所示:
List<Item> itemlist;
itemList = itemlist.OrderBy(item=>item.X, new EpsilonComparer(0.352))
.ThenBy (item=>item.Y, new EpsilonComparer(1.743)).ToList();
排序是否会像预期的那样,首先按 X 排序列表,然后按 Y 排序,同时将大致相等的值视为完全相等?
它会在某些情况下爆炸吗?
还是整个排序不明确?
使用没有传递性的 IComparer 究竟会产生什么后果?
(我知道这很可能是 c# 语言的未定义行为。我仍然对答案非常感兴趣。)
还有其他方法可以实现这种排序行为吗?
(除了四舍五入的值,这会在两个接近双打时引入伪影,一个向上取整,另一个向下取整)
此问题中代码的在线文件可用here:
【问题讨论】:
-
用物品试试吧
{ 0.3, 1.5 }, { 0.6, 4.5 }, { 0.9, 3 }看看你会得到什么 -
@kevingessner 我看到了这个问题,我不认为这是重复的。我特意问的是使用非传递性 IComparer 的后果是什么。
-
@ohmusama 输出是
(0.3, 1.5) (0.6, 4.5) (0.9, 3),这是我所期望的,但这并不能说明一般情况。 (代码可在线测试here) -
结果是可能相同数据的非确定性排序顺序。此外,在某些用途中,非传递比较器可能会导致无限循环。
标签: c# linq sorting undefined-behavior internals