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

问题描述 投票:2回答:4

我的原始数据如下所示:

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()
      });
}
c# linq enums
4个回答
1
投票

你正在过滤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();

1
投票

有时一个简单的嵌套qazxsw poi仍然是最好和最清晰的解决方案。在大多数情况下,它将使用大型数据集,比LINQ解决方案更快。

foreach

1
投票

在查询的第一部分中,您只获取集合中的第一个项目。然后你分组哪个是错的。试试以下:

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);
        }
    }
}

1
投票

我使用下面的代码来实现你的期望:

        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();

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();

© www.soinside.com 2019 - 2024. All rights reserved.