2017-03-17 48 views
1

我点的List,我想计算出使用LINQ结束的剩余距离(给出的指标):结合骨料和选择的LINQ

double remainingToEnd = Points.Skip(CurrentIndex).Aggregate((x, y) => x.DistanceTo(y)); 

这并不编译:

不能将lambda表达式转换为预期的委托类型,因为 块中的某些返回类型不能隐式转换 到委托返回类型

我通常通过使用Select扩展来解决这种情况,但这会阻止我计算之后的距离。

这很容易通过使用循环来实现,但我想知道是否可以用一些简单的Linq。我想避免匿名类型。


点的定义如下:

public class Point 
{ 
    public float X { get; set; } 
    public float Y { get; set; } 
    public float Z { get; set; } 

    public float DistanceTo(Point p2) 
    { 
     float x = this.X - p2.X; 
     float y = this.Y - p2.Y; 
     float z = this.Z - p2.Z; 

     return (float)Math.Sqrt((x * x) + (y * y) + (z * z)); 
    } 
} 
+1

嗨,什么是'DistanceTo'的返回类型? – Christos

+0

对不起,这是一个双重的 – Sturm

+0

没有问题:)只是想要更多的信息。谢谢 – Christos

回答

1

假设你想计算的收集点之间总距离(从某个索引开始)。你需要每一步的前一点。您可以通过zipping点收集与自身得到它:

double remainingToEnd = Points.Skip(CurrentIndex) 
           .Zip(Points.Skip(CurrentIndex + 1), (x,y) => x.DistanceTo(y)) 
           .Sum(); 

邮编会产生对出发点和落脚点的。结果选择器功能将选择每对的点之间的距离。然后你只需计算总和或距离。


你可以用聚合来解决这个任务,但是你需要在每一步中存储最后一个点。因此,你需要蓄能器将保持双方目前的距离和最后一点:

var remainingToEnd = Points.Skip(CurrentIndex).Aggregate(
      new { total = 0.0, x = Points.Skip(CurrentIndex).FirstOrDefault() }, 
      (a, y) => new { total = a.total + a.x.DistanceTo(y), x = y }, 
      a => a.total); 

而且记住,这Skip意味着仅仅通过项目迭代的序列项目没有做任何事情。如果你有很多积分,跳过两次会伤害你的表现。所以,如果你有个名单和性能问题,则循环简单的将做的工作:

double remainingToEnd = 0.0; 
for(int i = CurrentIndex; i < Points.Count - 1; i++) 
    remainingToEnd += Points[i].DistanceTo(Points[i+1]); 
+0

谢谢,当你和一个简单循环相比时,你对性能有什么看法:'for(int i = CurrentIndex; i Sturm

+0

@简单循环的Sturm性能总是优于LINQ性能。在内部它也使用循环,但也有一些对象创建和附加的方法调用在后台。 LINQ为您提供紧凑和富有表现力的代码。除非你有高负载系统持续运行这段代码,否则不要认为会有巨大的性能差异 –

0

试试这个:

double remainingToEnd = Points.Skip(CurrentIndex).Sum(point => point.DistanceTo(Points[Points.Findindex(p => p == point) - 1]));