【问题标题】:Delegate for LINQ ExtensionsLINQ 扩展的委托
【发布时间】:2015-03-22 10:32:34
【问题描述】:

在我的代码库中,我有大量的类需要对其成员执行各种集体操作以获得结果(平均值、标准差、置信区间等)

AverageLINQ Extension方法已经存在,而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);
    }

但是,我无法通过这些代表调用AverageStandardDeviation,大概是因为this 关键字。从 StandardDeviation 实现中删除它并将调用替换为以下内容:

BufferMinimumTime = Operation(samples, sample => sample.BufferMinimumTime);

它仍然不适合委托,产生以下错误消息:

Expected a method with 'double StandardDeviation(IEnumerable<ThisType>, Func<ThisType, double>)' signature.

我有什么方法可以为上述通用静态 LINQ 扩展创建委托吗?这些方法将以独特的方式在各种类中使用,因此它们必须是通用的。

【问题讨论】:

  • 我设法让它与您对CollectiveOperation&lt;T&gt;StandardDeviation&lt;T&gt;、库存Enumerable.Average&lt;T&gt; 的定义以及T 的小型测试类一起使用。您能否将您的问题浓缩为一个示例,其中包含重现问题所需的最少代码量?
  • 首先你的StandardDeviation 扩展应该使用yield return而不是完整的collection return,在网上查找。其次,您可以使用反射并获取样本中名称与本地成员匹配的成员列表,然后调用平均方法将结果分配给本地成员。
  • @Franck StandardDeviation 只需要返回单个值而不是序列时如何使用yield return
  • 哦,我明白你的意思,但看到他需要连续调用该列表 12 次,这对我来说是一次迭代,很容易在方法中作为列表并返回相同的列表计算出来的。

标签: c# .net linq delegates anonymous-function


【解决方案1】:

这让我想起了一点 MapReduce。您有一组要映射(例如,选择对象的单个属性)到数值的对象,然后您希望将此新的数值集合减少为单个数值。你可以定义一个 Wrapper-Method (为了更容易使用):

    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-方法如下:

    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);
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-03
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    相关资源
    最近更新 更多