使用linq计算列表属性的总和,不包括最小值和最大值

时间:2015-02-11 22:03:24

标签: c# linq list linq-to-objects

这是我到目前为止所做的:

decimal? total = list.Sum(item => item.Score);

我想要做的是排除列表中的最小值和最大值,然后获取总值。

是否可以在一个linq语句中完成所有这些操作?

5 个答案:

答案 0 :(得分:10)

list.OrderBy(item => item.Score)
    .Skip(1)
    .Reverse()
    .Skip(1)
    .Sum(item => item.Score);

答案 1 :(得分:5)

您可以先尝试排序列表,然后跳过第一项(最小值),然后从剩下的那一项中取出最后一项(最多):

decimal? total = list.OrderBy(x => x.Score)
                     .Skip(1)
                     .Take(list.Count - 2)
                     .Sum(x => x.Score);

答案 2 :(得分:1)

这不是可以想象的最好的代码,但它确实具有

的好处
  • 仅枚举整个集合一次(虽然它确实获得了第一个值三次)。
  • 不需要比保存IEnumerator和两个Tuple<int, int, long, long>对象(如果使用OrderByToList和排序等)不具有的内存。这使它可以使用任意大的IEnumerable集合。
  • 单个Linq表达式(这是你想要的)。
  • 正确处理边缘情况(values.Count() < 2):
    • 当没有值时,在IEnumerable上使用Min()Max()会抛出InvalidOperationException
    • 当有一个值时,天真的实现将在IEnumerable上执行类似Sum() - Min() - Max()的操作,返回单个值,否定。

我知道你已经接受了答案,但现在是:我正在使用Enumerable.Aggregate的一个电话。

public static long SumExcludingMinAndMax(IEnumerable<int> values)
{
    // first parameter: seed (Tuple<running minimum, running maximum, count, running total>)
    // second parameter: func to generate accumulate
    // third parameter: func to select final result
    var result = values.Aggregate(
            Tuple.Create<int, int, long, long>(int.MaxValue, int.MinValue, 0, 0),
            (accumulate, value) => Tuple.Create<int, int, long, long>(Math.Min(accumulate.Item1, value), Math.Max(accumulate.Item2, value), accumulate.Item3 + 1, accumulate.Item4 + value),
            accumulate => accumulate.Item3 < 2 ? 0 : accumulate.Item4 - accumulate.Item1 - accumulate.Item2);

    return result;
}

答案 3 :(得分:0)

如果您要排除所有最小值和最大值,请预先计算这两个值,然后使用Ènumerable.Where排除它们:

decimal? min = list.Min(item => item.Score);
decimal? max = list.Max(item => item.Score);
decimal? total = list
    .Where(item=> item.Score != min && item.Score != max)
    .Sum(item =>  item.Score);

答案 4 :(得分:-2)

您应该在总和之前预处理列表以排除最小和最大。