C#实现月度平均能耗值计算的技术方案咨询
如何计算月度平均能耗值
我有一个包含DateEnergyValue类实例的列表,类定义如下:
public class DateEnergyValue { public DateOnly CollectedDate{ get; set; } public double Value { get; set; } } List<DateEnergyValue> DateEnergyValues = new List<DateEnergyValue>() { /* 数据填充 */ }
需求是计算月度平均能耗值,计划步骤:
- 找出所有数据的起止日期并计算年份跨度
- 按月份分组计算平均能耗,同一月份多条数据取平均值
已实现起止日期和年份数的计算:
var startDate = DateEnergyValues.Min(a => a.CollectedDate); var endDate = DateEnergyValues.Max(r=>r.CollectedDate); // 修正:原代码startDate - endDate会得到负数,应该用endDate减startDate TimeSpan TS = endDate - startDate; double Years = TS.TotalDays / 365.25;
但不清楚后续分组计算逻辑,以下是示例数据:
| 采集日期(月/日/年) | 能耗值 |
|---|---|
| 5/1/2009 | 2400 |
| 6/1/2009 | 2400 |
| 7/1/2009 | 2400 |
| 8/1/2009 | 7315.8 |
| 9/1/2009 | 5140.3 |
| 10/1/2009 | 1557.8 |
| 11/1/2009 | 1557.8 |
| 12/1/2009 | 369.7 |
| 1/1/2010 | 369.7 |
| 2/1/2010 | 144.8 |
| 3/1/2010 | 437.2 |
| 4/1/2010 | 804.1 |
| 5/1/2010 | 965.1 |
| 6/1/2010 | 1131 |
| 7/1/2010 | 1179.4 |
| 8/1/2010 | 1170.8 |
| 9/1/2010 | 993.6 |
| 10/1/2010 | 714.9 |
| 11/1/2010 | 244.3 |
| 12/1/2010 | 126.8 |
| 1/1/2011 | 122.1 |
| 2/1/2011 | 114.6 |
| 3/1/2011 | 185.2 |
| 4/1/2011 | 441.9 |
| 5/1/2011 | 1494.9 |
| 6/1/2011 | 1009.9 |
| 7/1/2011 | 3051.3 |
| 8/1/2011 | 3229.7 |
| 9/1/2011 | 996 |
| 10/1/2011 | 3328.7 |
| 11/1/2011 | 870.1 |
| 12/1/2011 | 1051.8 |
| 4/1/2011 | 481000 |
| 5/1/2011 | 446000 |
| 6/1/2011 | 608000 |
| 7/1/2011 | 323000 |
| 8/1/2011 | 478000 |
| 9/1/2011 | 452000 |
| 10/1/2011 | 505000 |
| 11/1/2011 | 438000 |
| 12/1/2011 | 456654 |
实现思路与代码
1. 基础分组计算(仅计算有数据的月份)
使用LINQ的GroupBy按年份+月份分组,然后对每组计算平均值:
// 按年和月分组,计算每组的平均值 var monthlyAverages = DateEnergyValues .GroupBy(item => new { item.CollectedDate.Year, item.CollectedDate.Month }) .Select(group => new { Year = group.Key.Year, Month = group.Key.Month, AverageValue = group.Average(item => item.Value) }) .OrderBy(result => result.Year) .ThenBy(result => result.Month) .ToList();
这段代码会输出所有存在数据的月份的平均能耗,并且按时间顺序排序。
2. 补全起止日期范围内的所有月份(包括无数据的月份)
如果需要显示起止日期之间的所有月份(即使该月没有数据,平均值设为0或null),可以先生成所有月份的序列,再和分组结果关联:
// 生成起止日期之间的所有月份 var allMonths = new List<DateOnly>(); var currentMonth = new DateOnly(startDate.Year, startDate.Month, 1); while (currentMonth <= endDate) { allMonths.Add(currentMonth); currentMonth = currentMonth.AddMonths(1); } // 关联分组数据,补全无数据月份的平均值 var completeMonthlyAverages = allMonths .Select(month => new { Year = month.Year, Month = month.Month, AverageValue = DateEnergyValues .Where(item => item.CollectedDate.Year == month.Year && item.CollectedDate.Month == month.Month) .DefaultIfEmpty() .Average(item => item?.Value ?? 0) // 无数据时设为0,若要null则改为item?.Value }) .ToList();
3. 注意事项
- 原代码中计算年份数时,
startDate - endDate会得到负的时间跨度,需修正为endDate - startDate才能得到正确的天数差。 - 如果数据中存在异常值(比如示例中2011年4月的481000),可以根据需求在分组前添加过滤逻辑,例如
Where(item => item.Value < 100000)排除异常大的值。
内容的提问来源于stack exchange,提问作者kumar425
相关产品推荐
相关产品推荐

