在我的代码库中,我有大量的类,需要对其成员执行各种集体操作才能获得结果(平均值,标准偏差,置信区间等)。Average
LINQ扩展方法已经存在,但是StandardDeviation
不存在,因此我按以下方式实现它:
public static double StandardDeviation<T>(this IEnumerable<T> source, Func<T, double> selector)
{
var average = source.Average(selector);
var sumOfSquares = source.Sum(sample => Math.Pow(selector(sample) - average, 2));
return Math.Pow(sumOfSquares, 0.5);
}
我想找到一种方法来为此函数定义一个委托,最好将其定义为LINQ扩展,以避免重复的代码。下面是这两种方法的当前用法示例:
public override void Average(IList<ThisType> samples)
{
TotalEntered = samples.Average(sample => sample.TotalEntered);
TotalExited = samples.Average(sample => sample.TotalExited);
MinimumContents = samples.Average(sample => sample.MinimumContents);
AverageContents = samples.Average(sample => sample.AverageContents);
MaximumContents = samples.Average(sample => sample.MaximumContents);
MinimumTime = samples.Average(sample => sample.MinimumTime);
AverageTime = samples.Average(sample => sample.AverageTime);
MaximumTime = samples.Average(sample => sample.MaximumTime);
StdDevTime = samples.Average(sample => sample.StdDevTime);
AverageNonZeroTime = samples.Average(sample => sample.AverageNonZeroTime);
PercentageWithinLimit = samples.Average(sample => sample.PercentageWithinLimit);
base.Average(samples);
}
public override void StandardDeviation(IList<ThisType> samples)
{
TotalEntered = samples.StandardDeviation(sample => sample.TotalEntered);
TotalExited = samples.StandardDeviation(sample => sample.TotalExited);
MinimumContents = samples.StandardDeviation(sample => sample.MinimumContents);
AverageContents = samples.StandardDeviation(sample => sample.AverageContents);
MaximumContents = samples.StandardDeviation(sample => sample.MaximumContents);
MinimumTime = samples.StandardDeviation(sample => sample.MinimumTime);
AverageTime = samples.StandardDeviation(sample => sample.AverageTime);
MaximumTime = samples.StandardDeviation(sample => sample.MaximumTime);
StdDevTime = samples.StandardDeviation(sample => sample.StdDevTime);
AverageNonZeroTime = samples.StandardDeviation(sample => sample.AverageNonZeroTime);
PercentageWithinLimit = queueSamples.StandardDeviation(sample => sample.PercentageWithinLimit);
base.StandardDeviation(samples);
}
我尝试为这些方法创建一个委托,如下所示:
public delegate double CollectiveOperation<T>(IEnumerable<T> source, Func<T, double> selector);
用于以下代码的近乎重复的替换:
public void Operation(IList<ThisType> samples, LINQExtensions.CollectiveOperation<ThisType> Operation)
{
BufferMinimumTime = samples.Operation(sample => sample.BufferMinimumTime);
BufferAverageTime = samples.Operation(sample => sample.BufferAverageTime);
BufferMaximumTime = samples.Operation(sample => sample.BufferMaximumTime);
BufferStdDevTime = samples.Operation(sample => sample.BufferStdDevTime);
TotalMinimumTime = samples.Operation(sample => sample.TotalMinimumTime);
TotalAverageTime = samples.Operation(sample => sample.TotalAverageTime);
TotalMaximumTime = samples.Operation(sample => sample.TotalMaximumTime);
TotalStdDevTime = samples.Operation(sample => sample.TotalStdDevTime);
base.Operation(samples);
}
但是,可能由于
Average
关键字,我无法通过这些委托调用StandardDeviation
或this
。从StandardDeviation
实现中删除该代码并将调用替换为以下内容后:BufferMinimumTime = Operation(samples, sample => sample.BufferMinimumTime);
它仍然不适合委托,会产生以下错误消息:
Expected a method with 'double StandardDeviation(IEnumerable<ThisType>, Func<ThisType, double>)' signature.
我有什么办法为上述通用静态LINQ扩展创建委托?这些方法将以独特的方式在各种类中使用,因此它们必须是通用的。
最佳答案
这使我想起了MapReduce。您具有要映射(例如,选择对象的单个属性)到数字值的对象的集合,然后要将此新的数字值的集合减少为单个数字的值。您可以定义一个包装方法(为了更容易使用):
public static TResult MapReduce<T, TMap, TResult>(this IEnumerable<T> source, Func<T, TMap> mapper, Func<IEnumerable<TMap>, TResult> reducer)
{
return reducer(source.Select(mapper));
}
定义
Operation
-Method如下: public void Operation(IEnumerable<TestClass> samples, Func<IEnumerable<double>, double> operation)
{
var foo = samples.MapReduce(s => s.Foo, operation);
var bar = samples.MapReduce(s => s.Bar, operation);
}
并调用:
this.Operation(new List<TestClass>(), Enumerable.Average);
this.Operation(new List<TestClass>(), MyLinqExtensions.StandardDeviation);
但是您必须实现您的
StandardDeviation
有点不同: internal static double StandardDeviation(this IEnumerable<double> source)
{
var average = source.Average();
var sumOfSquares = source.Sum(sample => Math.Pow(sample - average, 2));
return Math.Pow(sumOfSquares, 0.5);
}