扩展方法,泛型列表上的SumIf<;T>;

本文关键字:lt gt SumIf 方法 泛型 列表 扩展 | 更新日期: 2023-09-27 18:28:04

我需要为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;
}

感谢您的指导,mort

扩展方法,泛型列表上的SumIf<;T>;

听起来你想要一种提取字符串属性和double属性的方法(假设你文章中的"decimal"是打字错误,而不是代码中的"double")-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<T>,因为实际上不需要它是列表。)

注意,这实际上相当于:

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

但是相当灵活。

正如评论中所指出的,你真的需要这个吗?你是否在足够多的地方使用它,让简单的Where/Sum调用变得难以忍受?见鬼,您可以使用条件运算符将其转换为Sum调用

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

您在方法中引入了一些非常具体的约束,使其不能是泛型的,例如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);