[英]Get sum of two columns in one LINQ query
假設我有一個名為Items的表(ID int,Done int,Total int)
我可以通過兩個查詢來完成:
int total = m.Items.Sum(p=>p.Total)
int done = m.Items.Sum(p=>p.Done)
但我想在一個查詢中執行此操作,如下所示:
var x = from p in m.Items select new { Sum(p.Total), Sum(p.Done)};
當然有一種方法可以從LINQ語法中調用聚合函數......?
這樣就可以了:
from p in m.Items
group p by 1 into g
select new
{
SumTotal = g.Sum(x => x.Total),
SumDone = g.Sum(x => x.Done)
};
要對表進行求和,請按常量分組:
from p in m.Items
group p by 1 into g
select new {
SumTotal = g.Sum(x => x.Total),
SumDone = g.Sum(x => x.Done)
}
怎么樣
m.Items.Select(item => new { Total = item.Total, Done = item.Done })
.Aggregate((t1, t2) => new { Total = t1.Total + t2.Total, Done = t1.Done + t2.Done });
弄清楚在我的其余代碼中提取總和或其他聚合的位置使我感到困惑,直到我記得我構造的變量是一個Iqueryable。 假設我們的數據庫中有一個由Orders組成的表,我們想為ABC公司生成一個摘要:
var myResult = from g in dbcontext.Ordertable
group p by (p.CUSTNAME == "ABC") into q // i.e., all of ABC company at once
select new
{
tempPrice = q.Sum( x => (x.PRICE ?? 0m) ), // (?? makes sure we don't get back a nullable)
tempQty = q.Sum( x => (x.QTY ?? 0m) )
};
現在有趣的部分 - tempPrice和tempQty沒有在任何地方聲明,但它們必須是myResult的一部分,不是嗎? 訪問它們如下:
Console.Writeline(string.Format("You ordered {0} for a total price of {1:C}",
myResult.Single().tempQty,
myResult.Single().tempPrice ));
還可以使用許多其他可查詢方法。
使用幫助器元組類,您可以使用自己的或者.NET 4 - 標准的那些:
var init = Tuple.Create(0, 0);
var res = m.Items.Aggregate(init, (t,v) => Tuple.Create(t.Item1 + v.Total, t.Item2 + v.Done));
res.Item1
是Done
列的Total
列和res.Item2
的Total
。
//Calculate the total in list field values
//Use the header file:
Using System.Linq;
int i = Total.Sum(G => G.First);
//By using LINQ to calculate the total in a list field,
var T = (from t in Total group t by Total into g select g.Sum(t => t.First)).ToList();
//Here Total is a List and First is the one of the integer field in list(Total)
這已經得到了回答,但是其他答案仍然會對集合進行多次迭代(多次調用Sum)或者創建大量的中間對象/元組可能沒問題,但如果不是,那么你可以創建一個擴展方法(或多個)以舊式方式執行,但非常適合LINQ表達式。
這樣的擴展方法如下所示:
public static Tuple<int, int> Sum<T>(this IEnumerable<T> collection, Func<T, int> selector1, Func<T, int> selector2)
{
int a = 0;
int b = 0;
foreach(var i in collection)
{
a += selector1(i);
b += selector2(i);
}
return Tuple.Create(a, b);
}
你可以像這樣使用它:
public class Stuff
{
public int X;
public int Y;
}
//...
var stuffs = new List<Stuff>()
{
new Stuff { X = 1, Y = 10 },
new Stuff { X = 1, Y = 10 }
};
var sums = stuffs.Sum(s => s.X, s => s.Y);
使用C#7.0中引入的元組語言支持,您可以使用以下LINQ表達式解決此問題:
var itemSums = m.Items.Aggregate((Total: 0, Done: 0), (sums, item) => (sums.Total + item.Total, sums.Done + item.Done));
完整代碼示例:
var m = new
{
Items = new[]
{
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
},
};
var itemSums = m.Items.Aggregate((Total: 0, Done: 0), (sums, item) => (sums.Total + item.Total, sums.Done + item.Done));
Console.WriteLine($"Sum of Total: {itemSums.Total}, Sum of Done: {itemSums.Done}");
當你使用group by Linq創建一個新的項目集合時,你有兩個項目集合。
這是兩個問題的解決方案:
碼:
public static class LinqExtensions
{
/// <summary>
/// Computes the sum of the sequence of System.Double values that are obtained
/// by invoking one or more transform functions on each element of the input sequence.
/// </summary>
/// <param name="source">A sequence of values that are used to calculate a sum.</param>
/// <param name="selectors">The transform functions to apply to each element.</param>
public static double[] SumMany<TSource>(this IEnumerable<TSource> source, params Func<TSource, double>[] selectors)
{
if (selectors.Length == 0)
{
return null;
}
else
{
double[] result = new double[selectors.Length];
foreach (var item in source)
{
for (int i = 0; i < selectors.Length; i++)
{
result[i] += selectors[i](item);
}
}
return result;
}
}
/// <summary>
/// Computes the sum of the sequence of System.Decimal values that are obtained
/// by invoking one or more transform functions on each element of the input sequence.
/// </summary>
/// <param name="source">A sequence of values that are used to calculate a sum.</param>
/// <param name="selectors">The transform functions to apply to each element.</param>
public static double?[] SumMany<TSource>(this IEnumerable<TSource> source, params Func<TSource, double?>[] selectors)
{
if (selectors.Length == 0)
{
return null;
}
else
{
double?[] result = new double?[selectors.Length];
for (int i = 0; i < selectors.Length; i++)
{
result[i] = 0;
}
foreach (var item in source)
{
for (int i = 0; i < selectors.Length; i++)
{
double? value = selectors[i](item);
if (value != null)
{
result[i] += value;
}
}
}
return result;
}
}
}
這是你必須做總結的方式:
double[] result = m.Items.SumMany(p => p.Total, q => q.Done);
這是一個一般的例子:
struct MyStruct
{
public double x;
public double y;
}
MyStruct[] ms = new MyStruct[2];
ms[0] = new MyStruct() { x = 3, y = 5 };
ms[1] = new MyStruct() { x = 4, y = 6 };
// sum both x and y members in one iteration without duplicating the array "ms" by GROUPing it
double[] result = ms.SumMany(a => a.x, b => b.y);
如你看到的
result[0] = 7
result[1] = 11
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.