如何返回Dictionary <string,dictionary <int,decimal>&gt;从这个方法?

时间:2016-01-28 12:42:55

标签: c# linq dictionary

我有一个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}}

如果有人需要更多信息,请告诉我。

1 个答案:

答案 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()或其他什么。