如何编写扩展函数以返回自定义类型的平均值?

Tom*_*ght 1 c# extension-methods average

这可能非常简单,但我的尝试(由Intellisense和MSDN指导)都是不合适的.

如果我有一个包含3个double的类,我怎样才能得到这些列表的平均值?

class DataPoint
{
    public int time;
    public int X;
    public int Y;
    public int Z;
    // Constructor omitted
}

class Main
{
    List<DataPoint> points = new List<DataPoint>();
    // Populate list
    DataPoint averagePoint = points.Average(someMagicHere);
}
Run Code Online (Sandbox Code Playgroud)

我想averagePoint遏制time,x,yz值是组成列表中元素的这些属性的平均值.我该怎么做呢?我正在努力的一点是(我认为)someMagicHere,但我可能完全使用错误的方法开始.

Eri*_*ert 6

问题并不完全清楚,但听起来你想要的是一个新的点P,其中PX是列表中各点的所有X坐标的平均值,依此类推,是吗?

解决这类问题的一般方法是将其分解:

首先将点列表转换为四个整数列表.

var times = from p in points select p.Time;
var xs = from p in points select p.X;
... and so on ..
Run Code Online (Sandbox Code Playgroud)

或者,如果您更喜欢这种表示法:

var times = points.Select(p=>p.Time);
Run Code Online (Sandbox Code Playgroud)

现在你可以平均那些:

double averageTime = times.Average();
double averageX = xs.Average();
... and so on ...
Run Code Online (Sandbox Code Playgroud)

现在你有四个值 - 就像双打一样 - 可以用来构建平均点.当然,您必须使用您喜欢的任何舍入将双精度转换为整数.

但是,有一个特殊版本的"平均值",它将Select和Average组合成一个操作.你可以说

double averageTime = points.Average(p=>p.Time);
Run Code Online (Sandbox Code Playgroud)

并且一步完成投影和平均值.

正如一些人所指出的,这种方法的缺点是序列被列举四次.这可能不是什么大问题,因为它是一个内存列表,但如果它是一个昂贵的数据库查询可能会更重要.

另一种方法是在DataPoint类上定义加法运算符(如果通常将两个点相加是有意义的,它可能不是).一旦有了加法运算符,就可以直接得出所有点的总和.

无论是否定义加法运算符,都可以使用" 聚合"来计算所有点的总和,然后将总和的四个字段除以点数.

DataPoint sum = points.Aggregate(
    new DataPoint(0, 0, 0, 0), 
    (agg, point)=> new DataPoint(agg.time + point.time, agg.x + point.x, ... ));
Run Code Online (Sandbox Code Playgroud)

或者,如果您有运营商,只需:

DataPoint sum = points.Aggregate(
    new DataPoint(0, 0, 0, 0), 
    (agg, point)=> agg + point);
Run Code Online (Sandbox Code Playgroud)

现在你有了总和,所以计算平均值很简单.