代码之家  ›  专栏  ›  技术社区  ›  Shahar Shokrani

嵌套字典:按日期分组,然后按枚举值分组并汇总计数

  •  2
  • Shahar Shokrani  · 技术社区  · 8 年前

    我的原始数据如下所示:

    IDictionary<DateTime, IDictionary<ReportType, int>> rawData
    

    例子:

    19/09/2017, [(ReportType.Open, 2)] 
    25/09/2017, [(ReportType.Open, 15), (ReportType.Sent, 15)] 
    25/10/2017, [(ReportType.Open, 27), (ReportType.Sent, 15)] 
    29/10/2017, [(ReportType.Sent, 150)]
    

    我正在努力实现以下结果:

    data for open:
    september-2017: 17
    october-2017: 27
    
    data for sent:
    september-2017: 15
    october-2017: 165
    -----------------------------
    

    我试过了

    var openData = rawData
        .Select(g => new {
            dt = string.Format("{0}/{1}", g.Key.Month, g.Key.Year),
            g.Key.Year,
            g.Key.Month,
            action = g.Value.FirstOrDefault().Key,
            total = g.Value.Values.Sum()
        })
        .GroupBy(l => new {
            l.Month,
            l.Year,
            action = l.action
        })
        .Where(a => a.Key.action == ReportType.Open)
        .OrderByDescending(a => a.Key)
        .ToList();
    

    我做错了什么?

    打印部分( series1 派生自 Series 类别):

    foreach (var item in openData)
    {
          series1.Points.Add(new DataPoint()
          {
              YValues = new double[] { item.total },
              AxisLabel = item.dt.ToString(),
              ToolTip = item.total.ToString()
          });
    }
    
    4 回复  |  直到 8 年前
        1
  •  1
  •   Emre Kabaoglu    8 年前

    您正在筛选 Open reporttype 错误的位置;

                var openData = rawData
                .Select(g => new {
                    dt = string.Format("{0}/{1}", g.Key.Month, g.Key.Year),
                    g.Key.Year,
                    g.Key.Month,
                    actions = g.Value.Where(x => x.Key == ReportType.Open) //Filter it here
                })
                .GroupBy(l => new {
                    l.Month,
                    l.Year
                })
                .Select(s =>
                new
                {
                    s.Key.Month,
                    s.Key.Year,
                    s.Sum(x => x.actions.Sum(sum => sum.Value))
                })
                .ToList();
    
        2
  •  1
  •   Keyur PATEL    8 年前

    有时一个简单的嵌套 foreach 仍然可以是最好的&最清晰的解决方案。在大多数情况下,对于大型数据集,它将比LINQ解决方案更快。

    Dictionary<string, int> openCounts = new Dictionary<string, int>();
    Dictionary<string, int> sentCounts = new Dictionary<string, int>();
    
    foreach (var kvp in rawData)
    {
        //var dt = string.Format("{0}-{1}", kvp.Key.ToString("MMMM"), kvp.Key.Year);
        var dt = kvp.Key.ToString("MMMM-yyyy");   //simpler alternative, "MMMM" gives full month name
        foreach (var val in kvp.Value)
        {
            if (val.Key == ReportType.Open)
            {
                if (openCounts.ContainsKey(dt))
                    openCounts[dt] += val.Value;
                else
                    openCounts.Add(dt, val.Value);
            }
            else
            {
                if (sentCounts.ContainsKey(dt))
                    sentCounts[dt] += val.Value;
                else
                    sentCounts.Add(dt, val.Value);
            }
        }
    }
    
        3
  •  1
  •   Seckin Celik    8 年前

    在查询的第一部分中,您只获取集合中的第一项。那么你分组是错误的。 请尝试以下操作:

            var ob = (from m in rawData
                      where m.Value.Keys.Any(i => i != ReportType.Sent)
                      group m by new { m.Key.Year, m.Key.Month, m.Value.Keys } into gx
                      select new
                      {
                          Date = new DateTime(gx.Key.Year, gx.Key.Month, 1),
                          //                          taa = gx.Key.Keys,
                          Total = gx.Select(m => m.Value.Values).ToList().Select(y => y.Sum()).FirstOrDefault()
                      }).ToList();
    
        4
  •  1
  •   shA.t Rami Jamleh    8 年前

    我使用以下代码来实现您的期望:

    var result = rawData
        .SelectMany(c => c.Value, (b, c) => new { b.Key.Year, Month = b.Key.ToString("MMMM"), c.Key, c.Value })
        // At first I unwind nested data
        .GroupBy(g => g.Key)
        // Then create my new group by ReportType
        .Select(c => new { 
            c.Key, 
            Data = c.GroupBy(g => new { g.Year, g.Month })
                    .Select(f => new { f.Key.Year, f.Key.Month, Sum = f.Sum(s => s.Value) })
            // Each ReportType has many groups of monthes of each year
        })
        // At last create my custom type
        .ToList();
    

    C# Fiddle Demo