【问题标题】:Extension method, SumIf on generic List<T>扩展方法,泛型 List<T> 上的 SumIf
【发布时间】:2012-03-17 22:52:52
【问题描述】:

我需要为 List(T) 编写一个通用扩展方法,它有条件地考虑 T 的每个字符串属性,然后在满足条件时对 T 的相应十进制属性求和。到目前为止我的努力:

// foreach(p in Persons) { if(p.Name == "mort"){sum p.Amount;} }

public static double SumIf<T>(this T o, List<T> ListItems, 
          string targetStr, ?strVals?, ?dblVals?)
{
    double sum = 0;
    foreach(T item in ListItems)
    {
        if(item.?strVal? == targetStr){ sum += item.?dblVal? ; }
    }
    return sum;
}

感谢您的指导, 死神

【问题讨论】:

  • 以上方法给你带来了什么问题?
  • Aggregate 不适合您吗?还是Where 后跟Sum?或者你想要一个辅助扩展方法?

标签: c# list generics extension-methods sum


【解决方案1】:

听起来您想要一种提取字符串属性和双精度属性的方法(假设您帖子中的“十进制”是错字而不是代码中的“双精度”)-Func 在这里是合适的:

public static double SumIf<T>(this IEnumerable<T> source, 
          string targetText,
          Func<T, string> textSelector,
          Func<T, double> valueSelector)
{
    double sum = 0;
    foreach (T item in source)
    {
        if (textSelector(item) == targetText)
        {
            sum += valueSelector(item);
        }
    }
    return sum;
}

(请注意,我已经删除了未使用的初始参数,并将其作为列表本身的扩展方法。不使用该值对我来说感觉有点异味......我还更改了参数类型到IEnumerable&lt;T&gt;,因为你真的不需要它是一个列表。)

请注意,这实际上几乎等同于:

public static double SumIf<T>(this IEnumerable<T> source, 
          string targetText,
          Func<T, string> textSelector,
          Func<T, double> valueSelector)
{
    return source.Where(x => textSelector(x) == targetText)
                 .Sum(valueSelector);
}

我个人可能会选择通用谓词函数而不是字符串和文本选择器:

public static double SumIf<T>(this IEnumerable<T> source, 
          Func<T, bool> predicate,
          Func<T, double> valueSelector)
{
    return source.Where(predicate)
                 .Sum(valueSelector);
}

然后你会调用它

double sum = list.SumIf(x => x.Name == "mort", x => x.Amount);

...这对我来说似乎和以下一样好:

double sum = list.SumIf("mort", x => x.Name, x => x.Amount);

...但要灵活得多。

正如 cmets 中所述,您真的需要这个吗?您是否在足够多的地方使用它以使简单的 Where/Sum 调用难以忍受?哎呀,您可以使用条件运算符将其转换为 Sum 调用:

double sum = list.Sum(x => x.Name == "mort" ? x => x.Amount : 0d);

【讨论】:

  • 一切都很好,除了在第二个实现中您调用 Select 并将列表类型更改为字符串,因此您无法调用 Sum 以获得 T 列表。
【解决方案2】:

您为您的方法引入了一些非常具体的约束,使其不能是通用的,例如T 必须有一个属性 Amount。最好将这些依赖项作为函数传递:

public static double SumIf<T>(this IList<T> source, 
                              Func<T, bool> pred, 
                              Func<T, double> val) 
{
    double sum = 0;
    foreach (var item in source)
        if (pred(item))
            sum += val(item);

    return sum;
}

然后您可以将您的谓词和总和属性选择器作为 lambdas 传递:

List<Person> people = new List<Person>();
people.Add(new Person() { Name = "Joe", Amount =20.2});
people.Add(new Person() { Name = "Fred", Amount = 11 });
people.Add(new Person() { Name = "Joe", Amount = 5.7 });

double sum = people.SumIf(x => x.Name == "Joe", x => x.Amount);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-15
    • 2014-12-21
    相关资源
    最近更新 更多