【发布时间】:2013-10-17 10:34:36
【问题描述】:
* 已解决 - 票在底部更新 *
我有一个“线”对象列表,每个对象都有一个“起点”和一个“终点”属性。这些属性包含标准点对象,每个对象都有一个“X”、“Y”和“Z”组件。
使用 Linq,我首先尝试通过升序任一端点的最小 Y 值,然后通过升序任一端点的最小 X 值(当 Y 值匹配时)来对列表进行排序。
我认为以下方法会起作用:
var sortedList = linesList
.OrderBy(o => Math.Min(o.StartPoint.Y, o.EndPoint.Y))
.ThenBy(o => Math.Min(o.StartPoint.X, o.EndPoint.X));
foreach (Line thisLine in sortedList)
{
Console.WriteLine(thisLine.StartPoint + ", " + thisLine.EndPoint);
}
但是,这会产生这个顺序(写成 xs、ys、zs、xe、ye、ze):
737.928, 825.293, 0, 737.928, 826.293, 0
737.616, 825.293, 0, 737.616, 826.293, 0
733.928, 825.293, 0, 733.928, 826.293, 0
733.616, 825.293, 0, 733.616, 826.293, 0
729.928, 825.293, 0, 729.928, 826.293, 0
729.616, 825.293, 0, 729.616, 826.293, 0
725.928, 825.293, 0, 725.928, 826.293, 0
725.616, 825.293, 0, 725.616, 826.293, 0
721.928, 825.293, 0, 721.928, 826.293, 0
721.616, 825.293, 0, 721.616, 826.293, 0
717.928, 825.293, 0, 717.928, 826.293, 0
717.616, 825.293, 0, 717.616, 826.293, 0
713.928, 825.293, 0, 713.928, 826.293, 0
713.616, 825.293, 0, 713.616, 826.293, 0
709.928, 825.293, 0, 709.928, 826.293, 0
709.616, 825.293, 0, 709.616, 826.293, 0
705.928, 825.293, 0, 705.928, 826.293, 0
705.616, 825.293, 0, 705.616, 826.293, 0
701.928, 825.293, 0, 701.928, 826.293, 0
701.616, 825.293, 0, 701.616, 826.293, 0
697.928, 825.293, 0, 697.928, 826.293, 0
697.616, 825.293, 0, 697.616, 826.293, 0
693.928, 825.293, 0, 693.928, 826.293, 0
693.616, 825.293, 0, 693.616, 826.293, 0
689.928, 825.293, 0, 689.928, 826.293, 0
689.616, 825.293, 0, 689.616, 826.293, 0
685.928, 825.293, 0, 685.928, 826.293, 0
685.616, 825.293, 0, 685.616, 826.293, 0
681.928, 825.293, 0, 681.928, 826.293, 0
681.616, 825.293, 0, 681.616, 826.293, 0
677.928, 825.293, 0, 677.928, 826.293, 0
677.616, 825.293, 0, 677.616, 826.293, 0
673.928, 825.293, 0, 673.928, 826.293, 0
673.616, 825.293, 0, 673.616, 826.293, 0
669.928, 825.293, 0, 669.928, 826.293, 0
669.616, 825.293, 0, 669.616, 826.293, 0
737.928, 826.481, 0, 737.928, 827.481, 0
737.616, 826.481, 0, 737.616, 827.481, 0
733.928, 826.481, 0, 733.928, 827.481, 0
733.616, 826.481, 0, 733.616, 827.481, 0
729.928, 826.481, 0, 729.928, 827.481, 0
729.616, 826.481, 0, 729.616, 827.481, 0
.
.
.
如您所见,“Y”值正确上升,但“X”值下降。
* 更新**
在 cmets 部分,提出了 OrderBy 比较器中典型的浮动容差问题的可能性。作为快速测试,我将 .OrderBy 子句更改为:
.OrderBy(o => Math.Min(Math.Round(o.StartPoint.Y, 3), Math.Round(o.EndPoint.Y, 3)))
这很丑,但它解决了排序问题。显然,没有一个“Y”值被视为相等。现在我已经强制它们四舍五入到 3 个位置,值真的 do 匹配,然后执行 ThenBy 子句以按“X”值排序。
现在,有什么更好的方法来强制匹配?编写我自己的比较器?
【问题讨论】:
-
你能用一个简短但完整的程序来展示这个吗?你确定某处的 X 值没有否定吗?
-
请提供代表 StartPoint 和 EndPoint 属性类型的类的名称和来源。是你写的吗,网上的一些人还是微软写的?如果您有源代码,请提供 ToString 方法并自己查看。 ToString 方法是否遵守 X、Y 和 Z 的顺序?如果您没有资源,那么您是否阅读了围绕该类及其随行人员的库的文档?
-
乔恩,感谢您的回复,但我不确定您在问什么(X 值中的否定)。没有在发布代码之前实际创建“行”对象列表,这实际上就是手头的所有问题。我可以使用我发布的代码对列表进行排序并打印出来,然后得到显示的结果。
-
@JeffGodfrey 您可以尝试在
Line类中为您的X和Y使用decimal,而不是当前使用的类型吗? -
@Eduard - 提供“Line”对象和“Point3D”对象的库是第三方商业 CAD 库。在这种情况下,我没有来源。虽然我相对有信心 Point3D.ToString() 保持正确的 X、Y、Z 顺序,但我肯定会验证这一点。