Home > Back-end >  calculate the monthly average
calculate the monthly average

Time:01-17

I have the below list that has an object with two properties, Date and energy value, and I have to calculate the average energy per month.

The steps I need to follow are to find the start date and end date among all these and find the number of years, and then, each month need to calculate the average energy. If I see multiple months, I need to average the energy value.

public class DateEnergyValue 
{
   public DateOnly CollectedDate{ get; set; }
   public double Value { get; set; }
}

List<DateEnergyValue> DateEnergyValues = new List<DateEnergyValue>() { .....} 

I can get the start date and end date like as below.

var startDate = DateEnergyValues.Min(a => a.CollectedDate);
var endDate = DateEnergyValues.Max(r=>r.CollectedDate);

I can get the number of years as well.

TimeSpan TS = startDate - endDate;
double Years = TS.TotalDays / 365.25; 

But not sure how to go about the remaining calculation, and below the sample data image

Collected Date(Month/Day/Year) Value
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

Could anyone please help with any ideas or suggestions with the same? Many thanks in advance!!

CodePudding user response:

I have an idea of ​​how I could do it I'm not sure about the performance of it but I could do it

        List<DateEnergyValue> teste = new List<DateEnergyValue>();

        var primeiro = teste.GroupBy(x => new { mounth = x.CollectedDate.Month })
                            .Select(x => 
                                         new { 
                                             media = x.Average(p => p.Value), 
                                             mounth = x.Key.mounth 
                                         })
                            .ToList();

the list would be grouped by month and then create a new list from the grouping with an average of the groupings by month that would result in the value that needs the monthly average...

Hope this helps

CodePudding user response:

After calculating the min and max date, you can iterate the months between those two dates and get an average for each one (leaving it zero if no matches were found for that month):

  static void Main(string[] args)
  {

    // the supplied data as a pipe and comma delimited string
    String data = 
      "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";

    List<DateEnergyValue> DateEnergyValues = new List<DateEnergyValue>();
    
    // this part just generates the list of instances:
    foreach(String pair in data.Split(",".ToCharArray())) {
      String[] values = pair.Split("|".ToCharArray());    
      DateEnergyValue dev = new DateEnergyValue();
      dev.CollectedDate = DateTime.ParseExact(values[0], "M/d/yyyy", null);
      dev.Value = double.Parse(values[1]);
      DateEnergyValues.Add(dev);      
    }

    // you provided this part:
    var minDate = DateEnergyValues.Min(a => a.CollectedDate);
    var maxDate = DateEnergyValues.Max(r => r.CollectedDate);

    List<DateEnergyValue> DateEnergyAverages = new List<DateEnergyValue>();
    
    DateTime startDate = new DateTime(minDate.Year, minDate.Month, 1);
    DateTime stopDate = new DateTime(maxDate.Year, maxDate.Month, 1);
    while (startDate <= stopDate) {
      DateEnergyValue devAverage = new DateEnergyValue();
      devAverage.CollectedDate = startDate;
      var monthValues = DateEnergyValues.Where(x => x.CollectedDate.Year == startDate.Year && x.CollectedDate.Month == startDate.Month);
      if (monthValues.Count() > 0) {
        devAverage.Value = monthValues.Average(x => x.Value);
      }
      DateEnergyAverages.Add(devAverage);
      startDate = startDate.AddMonths(1);
    }

    foreach(DateEnergyValue dev in DateEnergyAverages) {
      Console.WriteLine(dev);
    }
  }

I added a ToString() to the class so it'll ouput:

using System;
public class DateEnergyValue 
{
  
  public DateTime CollectedDate{ get; set; }
  public double Value { get; set; }

  public override String ToString() {
    return $"Date: {CollectedDate.ToString("M/d/yyyy")}, Value: {Value}";
  }
  
}

The generated output:

Date: 5/1/2009, Value: 2400
Date: 6/1/2009, Value: 2400
Date: 7/1/2009, Value: 2400
Date: 8/1/2009, Value: 7315.8
Date: 9/1/2009, Value: 5140.3
Date: 10/1/2009, Value: 1557.8
Date: 11/1/2009, Value: 1557.8
Date: 12/1/2009, Value: 369.7
Date: 1/1/2010, Value: 369.7
Date: 2/1/2010, Value: 144.8
Date: 3/1/2010, Value: 437.2
Date: 4/1/2010, Value: 804.1
Date: 5/1/2010, Value: 965.1
Date: 6/1/2010, Value: 1131
Date: 7/1/2010, Value: 1179.4
Date: 8/1/2010, Value: 1170.8
Date: 9/1/2010, Value: 993.6
Date: 10/1/2010, Value: 714.9
Date: 11/1/2010, Value: 244.3
Date: 12/1/2010, Value: 126.8
Date: 1/1/2011, Value: 122.1
Date: 2/1/2011, Value: 114.6
Date: 3/1/2011, Value: 185.2
Date: 4/1/2011, Value: 240720.95
Date: 5/1/2011, Value: 223747.45
Date: 6/1/2011, Value: 304504.95
Date: 7/1/2011, Value: 163025.65
Date: 8/1/2011, Value: 240614.85
Date: 9/1/2011, Value: 226498
Date: 10/1/2011, Value: 254164.35
Date: 11/1/2011, Value: 219435.05
Date: 12/1/2011, Value: 228852.9
  • Related