简体   繁体   English

Linq - 按几个包含的属性对对象列表进行排序

[英]Linq - Sort list of objects by several contained properties

* Resolved - Ticket updated at bottom * *已解决 - 机票在底部更新*

I have a list of "line" objects, each with a "StartPoint" and an "EndPoint" property. 我有一个“行”对象列表,每个对象都有一个“StartPoint”和一个“EndPoint”属性。 Those properties contain standard point objects, each with an "X", "Y", and "Z" component. 这些属性包含标准点对象,每个对象都带有“X”,“Y”和“Z”组件。

Using Linq, I'm trying to sort my list first by ascending minimum Y value of either end point, then by ascending minimum X value of either endpoint (when the Y values match). 使用Linq,我首先尝试通过提升任一端点的最小Y值,然后通过提升任一端点的最小X值(当Y值匹配时)对列表进行排序。

I thought the following would work: 我认为以下内容可行:

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);
}

However, that produces this order (written as xs, ys, zs, xe, ye, ze): 但是,这会产生这个顺序(写成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
.
.
.

As you can see, the "Y" values are ascending properly, but the "X" values are descending. 如您所见,“Y”值正确递增,但“X”值正在下降。

* UPDATE ** *更新**

In the comments section,the possibility of typical float tolerance issues in the OrderBy comparer was raised. 在注释部分,提出了OrderBy比较器中典型浮动容差问题的可能性。 As a quick test, I changed the .OrderBy clause to this: 作为一个快速测试,我将.OrderBy子句更改为:

.OrderBy(o => Math.Min(Math.Round(o.StartPoint.Y, 3), Math.Round(o.EndPoint.Y, 3))) .OrderBy(o => Math.Min(Math.Round(o.StartPoint.Y,3),Math.Round(o.EndPoint.Y,3)))

It's ugly, but it fixed the sort issue. 这很难看,但它解决了排序问题。 Apparently, none of the "Y" values were being seen as equal. 显然,没有一个“Y”值被视为平等。 Now that I've forced them to round to 3 places, the values really do match and the ThenBy clause is executed to sort by "X" value. 现在,我已经迫使他们舍入到3个地方,值确实匹配,并执行ThenBy条款由“X”的值进行排序。

Now, what's a better way to force the match? 现在,强迫比赛的更好方法是什么? Write my own comparer? 写我自己的比较器?

I'll answer the updated question: 我会回答更新的问题:

If you want to perform custom comparison to order based on rounded values without modifying the actual values, you can implement IComparer<T> . 如果要在不修改实际值的情况下根据舍入值执行自定义比较,则可以实现IComparer<T> Then use the overload of OrderBy<T> that takes an IComparer. 然后使用带有IComparer OrderBy<T>重载

public class NonExactLineComparer : IComparer<Line>
{
    public int Compare(Line x, Line y)
    {
        // Comparison logic
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM