结合Aggregate和Select Linq

时间:2017-03-17 21:36:42

标签: c# linq select aggregate

我有一个List分,我想用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));
    }
}

2 个答案:

答案 0 :(得分:1)

假设您要计算集合中点之间的总距离(从某个索引开始)。每一步都需要前一点。您可以通过zipping点集合获取它:

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

Zip将产生成对的起点和终点。结果选择器功能将选择每对点之间的距离。然后你只计算总和或距离。

您可以使用聚合来解决此任务,但您需要在每个步骤中存储最后一个点。所以你需要累加器来保持当前距离和最后一点:

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意味着只是按项目迭代您的序列而不做任何事情。如果你有很多积分,跳过两次可能会损害你的表现。因此,如果您有点列表和性能问题,那么简单的for循环将完成这项工作:

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

答案 1 :(得分:0)

试试这个:

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