Reputation: 4125
I have a List
of points and I want to calculate the remaining distance to the end using Linq (given an index):
double remainingToEnd = Points.Skip(CurrentIndex).Aggregate((x, y) => x.DistanceTo(y));
This doesn't compile:
Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type
I normally solve this situation projecting by using the Select extension, but that would prevent me from calculating the distance afterwards.
This is easily achieved by using a loop but I want to know if it is possible with some simple Linq. I would like to avoid anonymous types too.
Point is defined like:
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));
}
}
Upvotes: 1
Views: 1571
Reputation: 236238
Assume you want to calculate total distance between points in collection (starting from some index). You need previous point on each step. You can get it by zipping points collection with itself:
double remainingToEnd = Points.Skip(CurrentIndex)
.Zip(Points.Skip(CurrentIndex + 1), (x,y) => x.DistanceTo(y))
.Sum();
Zip will produce pairs of starting and ending points. Result selector function will select distance between points for each pair. And then you just calculate sum or distances.
You can solve this task with aggregation as will, but you need to store last point on each step. So you need accumulator which will keep both current distance and last point:
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);
And keep in mind, that Skip
means just iterating your sequence item by item without doing anything. If you have a lot of points, skipping twice can hurt your performance. So if you have list of points, and performance matters, then simple for loop will do the job:
double remainingToEnd = 0.0;
for(int i = CurrentIndex; i < Points.Count - 1; i++)
remainingToEnd += Points[i].DistanceTo(Points[i+1]);
Upvotes: 1
Reputation: 1507
Try this:
double remainingToEnd = Points.Skip(CurrentIndex).Sum(point => point.DistanceTo(Points[Points.Findindex(p => p == point) - 1]));
Upvotes: 0