我有一个LINQ语句,它返回下面类的IQueryable。
类别:
public class SupplierSummaryReport {
public int Year { get; set; }
public string SupplierName { get; set; }
public decimal TurnOverValues { get; set; }
}
例如:{2012,Supplier1,90},{2011,Supplier2,95}
但是,我需要将此数据转换为词典词典。我有我和朋友建立的扩展方法,但我们在最后一节难倒。
扩展方法:
public static Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>> Pivot<TSource, TFirstKey, TSecondKey, TValue>(this IEnumerable<TSource> source, Func<TSource, TFirstKey> firstKeySelector, Func<TSource, TSecondKey> secondKeySelector, Func<TSource, TValue> Value) {
var retVal = new Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>>();
var l = source.ToLookup(firstKeySelector);
foreach (var item in l) {
var dict = new Dictionary<TSecondKey, TValue>();
retVal.Add(item.Key, dict);
var subdict = item.ToLookup(secondKeySelector);
foreach (var subitem in subdict) {
dict.Add(subitem.Key, subitem.Value /*Insert value here*/);
}
}
return retVal;
}
我们这样称呼方法:
public Dictionary<string,Dictionary<int,decimal>> GetSupplierSummaryReportData(List<int> last5Years) {
_ctx.Database.CommandTimeout = 5 * 60;
//values - Gets the data required for the Supplier summary report in a hierachical order. E.g - {2012,Supplier1,3},{2011,Supplier1,4}
var values = (from i in _ctx.Invoices
where i.Turnover == true
group i by new { i.AccountName, i.InvoiceDate.Year } into summ
select new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = summ.Key.Year,
SupplierName = summ.Key.AccountName,
TurnOverValues = summ.Sum(r => r.VATAmount_Home ?? 0)
});
//accounts - Get all the account names
var accounts = (from i in _ctx.Invoices
where i.Turnover == true
group i by new { i.AccountName } into summ
select new {
summ.Key.AccountName
});
/*crossJoin - select all SupplierNames from accounts and all years from last5Years and assign each SupplierName the last 5 years. Assign each turnover value null for each year.
This is in preparation for the cross join as not all suppliers will have the last 5 year in data */
var crossJoin = accounts.SelectMany(a => last5Years, (a, y) => new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = y,
SupplierName = a.AccountName,
TurnOverValues = 0
});
/*Join crossJoin and values together, wherever the join is empty, assign the cross join values. If not assign the turnover value from a*/
var result =
(from cj in crossJoin
join v in values
on new { cj.Year, cj.SupplierName }
equals new { v.Year, v.SupplierName } into lJoin
from a in lJoin.DefaultIfEmpty(new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = cj.Year,
SupplierName = cj.SupplierName,
TurnOverValues = cj.TurnOverValues
})
select new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = cj.Year,
SupplierName = cj.SupplierName,
TurnOverValues = a.TurnOverValues
}).OrderBy(r => r.SupplierName).ThenBy(r => r.Year);
return result.Pivot(r => r.SupplierName, c => c.Year, y => y.TurnOverValues);
我们需要插入TurnOverValues
的十进制值作为字典中的第三项。
预期结果:
{Supplier1, {2012,60}}, {Supplier2, {2014,90}}
如果有人需要更多信息,请告诉我。
答案 0 :(得分:3)
TL; DR,但如果您拥有的是IEnumerable<SupplierSummaryReport>
,并且您确定每个SupplierName, Year, TurnOver
组合都是唯一的,或者可以使其成为唯一,那么ToDictionary
可以轻松实现这一目标:< / p>
var data = new List<SupplierSummaryReport> { ... };
// avoiding var just to verify correct result Type
Dictionary<string, Dictionary<int, decimal>> result = data
.GroupBy(ssr => ssr.SupplierName)
.ToDictionary(g1 => g1.Key, g1 => (
g1.GroupBy(g2 => g2.Year)
.ToDictionary(g3 => g3.Key,
g3 => g3.First().TurnOverValues))
);
也许g3.First()
应该成为.Single()
或.Sum()
或其他什么。