Linq找到长度最长的一对点?

时间:2010-03-31 15:46:31

标签: c# linq

我有以下代码:

foreach (Tuple<Point, Point> pair in pointsCollection)
        {
            var points = new List<Point>()
                        {
                            pair.Value1,
                            pair.Value2
                        };

        }

在这个foreach中,我希望能够确定哪一对点在该对中每个点的坐标之间具有最显着的长度。

所以,让我们说积分由以下几对构成:

(1)var points = new List<Point>() { new Point(0,100), new Point(100,100) };

(2)var points = new List<Point>() { new Point(150,100), new Point(200,100) };

所以我有两组配对,如上所述。他们都将绘制一条水平线。我有兴趣知道最好的方法是找到距离最大的那对点,无论是垂直还是水平。在上面的两个示例中,第一对点在X坐标之间具有100的差异,因此这将是具有最显着差异的点。但是,如果我有一对点的集合,其中一些点将绘制一条垂直线,一些点将绘制一条水平线,这是从差异的一组点中再次垂直或水平检索该对的最佳方法,是该系列中所有要点中最大的一个?

谢谢!

克里斯

4 个答案:

答案 0 :(得分:3)

使用OrderBy根据您的条件创建订单,然后选择第一个。在这种情况下,按降序排列水平和垂直分量之间的最大绝对差值。

编辑:实际上,我认为你应该在元组本身上这样做,对吧?我将努力使这个例子适应那个。

首先,让我们为Tuple<Point,Point>添加一个扩展来计算它的长度。

 public static class TupleExtensions
 {
      public static double Length( this Tuple<Point,Point> tuple )
      {
          var first = tuple.Item1;
          var second = tuple.Item2;
          double deltaX = first.X - second.X;
          double deltaY = first.y - second.Y;
          return Math.Sqrt( deltaX * deltaX + deltaY * deltaY );
      }
}

现在我们可以按长度订购元组

var max = pointCollection.OrderByDescending( t => t.Length() )
                         .FirstOrDefault();

注意:迭代集合并跟踪最大值而不是使用LINQ排序/选择更快。

Tuple<Point,Point> max = null;
foreach (var tuple in pointCollection)
{
     if (max == null || tuple.Length() > max.Length())
     {
         max = tuple;
     }
}

显然,如果您在多个地方使用它,可以将其重构为IEnumerable扩展。

答案 1 :(得分:2)

你可能需要一个函数,可能使用毕达哥拉斯定理来计算距离

a ^ 2 + b ^ 2 = c ^ 2

如果一个是Point.X的差异,b将是Point.Y的差异,c将是你的距离。一旦编写了该函数,就可以转到LINQ并对结果进行排序。

这就是我的所作所为。 (注意:我没有C#4,所以它不是苹果到苹果

private double GetDistance(Point a, Point b)
{
    return Math.Pow(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2), 0.5);
}

如果您愿意,可以将其转换为匿名方法或Func。

var query = pointlistCollection.OrderByDescending(pair => GetDistance(pair[0], pair[1])).First();

如果pointlistCollection是List<List<Point>>,则每个内部列表都有两个项目。快速举例,但它确实有效。

List<List<Point>> pointlistCollection 
    = new List<List<Point>>()
    {
        new List<Point>() { new Point(0,0), new Point(3,4)},
        new List<Point>() { new Point(5,5), new Point (3,7)}
    };

***这是我在Func表单中的GetDistance函数。

Func<Point, Point, double> getDistance
        = (a, b)
        => Math.Pow(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2), 0.5);

var query = pointlistCollection.OrderByDescending(pair => getDistance(pair[0], pair[1])).First();

答案 2 :(得分:0)

如上所述:不要对列表进行排序以获得最大值。

public static double Norm(Point x, Point y)
{
  return Math.Sqrt(Math.Pow(x.X - y.X, 2) + Math.Pow(x.Y - y.Y, 2));
}

Max()只需要O(n)而不是O(n * log n)

pointsCollection.Max(t => Norm(t.Item1, t.Item2));

答案 3 :(得分:-1)

tvanfosson的答案很好,但是我想建议稍微改进一下:你实际上不需要对集合进行排序以找到最大值,你只需要枚举集合并跟踪最大值。由于这是一个非常常见的场景,我编写了一个扩展方法来处理它:

public static class EnumerableExtensions
{
    public static T WithMax<T, TValue>(this IEnumerable<T> source, Func<T, TValue> selector)
    {
        var max = default(TValue);
        var withMax = default(T);
        bool first = true;
        foreach (var item in source)
        {
            var value = selector(item);
            int compare = Comparer<TValue>.Default.Compare(value, max);

            if (compare > 0 || first)
            {
                max = value;
                withMax = item;
            }
            first = false;
        }
        return withMax;
    }
}

然后你可以这样做:

Tuple<Point, Point> max = pointCollection.WithMax(t => t.Length());