按坡度对点列表进行排序

时间:2016-02-02 21:55:18

标签: c# sorting

在环顾StackOverflow时,我发现了一些按一个属性排序列表的例子,或者点之间的距离排序,但没有斜率排序。我对C#不是很熟悉,也很乐意帮忙。

我有一个点列表: (1,1)(2,5)(3,3)(7,1)

这看起来像这样:

--x-----
--------
---x----
--------
-x-----x
--------

我想计算从最左边的点(1,1)到另一个点的斜率:

  • (1,1)至(2,5)
  • (1,1)至(3,3)
  • (1,1)至(7,1)

然后按降序对它们进行排序。

斜率由y中的增益除以x中的增益("运行中的上升")确定。

斜坡会产生以下结果:

  • (1,1)至(2,5)=> 4/1 = 4
  • (1,1)至(3,3)=> 2/2 = 1
  • (1,1)至(7,1)=> 0/6 = 0

如何使用C#执行此操作?

我已经能够做到这一点:numbers.OrderBy(p => p.X);并且我认为解决方案应该是这样的:

Point anchorPoint = new Point(1,1);
numbers = numbers.OrderBy(p => (p.Y - anchorPoint.Y)/(p.X - anchorPoint.X));

但是还没有能够解决这个问题。

2 个答案:

答案 0 :(得分:1)

你很接近 - 你只需要将“锚点”作为列表中的第一个点,并在前面放置任何“无限”斜坡:

Point anchorPoint = numbers[0];
var query = 
     numbers.Select((p,i) => new {p,i})  // to get the index of each point
            .OrderBy(pi => pi.i == 0 ? 0 : 1)  // keep the first point first
            .ThenByDescending(pi => (pi.p.X == anchorPoint.X) ? double.PositiveInfinity 
                                                              : (pi.p.Y * 1.0 - anchorPoint.Y)/(pi.p.X - anchorPoint.X))  // infinite slopes first, the finite slopes descending
            .Select(pi => p);

请注意,我将其中一个值乘以1.0,以将整数 divison转换为浮点除法。

您也可以“跳过”第一个点,订购其余点,然后连接结果:

var query = 
     numbers.Take(1).Concat(
     numbers.Skip(1)
            .OrderByDescending(p => (p.X == anchorPoint.X) ? double.PositiveInfinity 
                                                           : (p.Y * 1.0 - anchorPoint.Y)/(p.X - anchorPoint.X))
     );

这有点干净,因为您没有对匿名类型的投影来包含索引。

答案 1 :(得分:0)

感谢所有出色的答案。

我弄清楚了我的错误:打字。

我试图将我的排序结果返回到我订购的列表中。 List和OrderedList之间存在脱节。为了解决这个问题,我添加了.ToList()来电。

numbers = numbers.OrderBy(p => (p.Y - anchorPoint.Y)/(p.X - anchorPoint.X)).ToList();