My raw data looks like this:
IDictionary<DateTime, IDictionary<ReportType, int>> rawData
Example:
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)]
I'm trying to achieve The following result:
data for open:
september-2017: 17
october-2017: 27
data for sent:
september-2017: 15
october-2017: 165
-----------------------------
I've tried to
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();
What am i doing wrong?
The Print section (series1
is derived from Series
class):
foreach (var item in openData)
{
series1.Points.Add(new DataPoint()
{
YValues = new double[] { item.total },
AxisLabel = item.dt.ToString(),
ToolTip = item.total.ToString()
});
}
答案 0 :(得分:1)
You are filtering the Open reporttype
wrong place;
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 :(得分:1)
Sometimes a simple nested foreach
can still be the best & clearest solution. It will, in most cases with large datasets, be quicker than LINQ solutions.
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);
}
}
}
答案 2 :(得分:1)
In the first part of your query, you are taking only first item in the collection. Then you are grouping which is wrong. Try below:
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();
答案 3 :(得分:1)
我使用下面的代码来实现您的期望:
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();