鉴于课程:
public class FooAmounts
int Id
decimal Month1
decimal Month2
...
decimal Month12
decimal Year2
decimal Year3
decimal Future
我有IEnumerable<FooAmounts>
有5个条目(Id的1-5足够有趣!)
我想创建一个新的FooAmounts,每个月/年的总数,但只有Id == 1 + Id == 2 e.g。
var footle = (from f in foolist
where f.Id == 1 || f.Id == 2
select new FooAmounts{
Month1 = Sum(month 1s),
Month2 = Sum(month 2s),
etc etc.
Future = Sum(futures)
).FirstOrDefault();
我正在尝试重新创建这个t-sql:
select SUM(Month1) as Month1, SUM(Month2) as Month2, SUM(Month3) as Month3 from FooAmount where Id=1 or Id=2"
我可以使用group by f.Id into grp
子句来实现类似但是我留下两个项目,因此我不能使用First / FoD,这意味着我必须手动将它们相加...这似乎我必须在某处错过了一招?
注意:FirstOrDefault()只在那里,所以我得到一个对象而不是一个包含一个对象的可枚举对象。我想(也许是错误的!)这应该总是只返回一个项目...只有一个Sum()的结果,无论有多少项进入计算。
答案 0 :(得分:1)
无论你有一个值还是多个值,取一笔总和的第一个结果都没有意义。
如果我有10个人,我可以找到第一个的年龄,或者我可以找到所有的年龄总和 - 但我找不到第一个年龄的总和。所以你可以这样做:
var matches = fooList.Where(f => f.Id == 1 || f.Id == 2);
var sum = new FooAmounts { Month1 = matches.Sum(f => f.Month1),
Month2 = matches.Sum(f => f>Month2),
... };
现在,这将多次执行查询。您可以改为实现查询,然后对其进行求和:
// Materialize the result so we only filter once
var matches = fooList.Where(f => f.Id == 1 || f.Id == 2).ToList();
var sum = new FooAmounts { Month1 = matches.Sum(f => f.Month1),
Month2 = matches.Sum(f => f>Month2),
... };
或者您可以使用聚合:
var sum = fooList.Where(f => f.Id == 1 || f.Id == 2)
.Aggregate(new FooAmounts(), // Seed
(sum, item) => new FooAmounts {
Month1 = sum.Month1 + item.Month1,
Month2 = sum.Month2 + item.Month2,
...
});
这只会迭代序列一次,而不是在内存中创建一个大缓冲区,但会在迭代时创建很多FooAmounts
个实例。
你可以修改累加器,当然:
var sum = fooList.Where(f => f.Id == 1 || f.Id == 2)
.Aggregate(new FooAmounts(), // Seed
(sum, item) => {
sum.Month1 += item.Month1;
sum.Month2 += item.Month2;
...
return sum;
});
感觉稍微对我很讨厌,但它确实没有副作用,因为它只是改变了在无论如何都要打电话。