Aggregating reading data on an hourly/daily/weekly basis and extending last-known value over missing intervals

StackOverflow https://stackoverflow.com/questions/23632369

  •  21-07-2023
  •  | 
  •  

Question

I have a table of Inspections which have Readings

Inspections
     |_ Readings : DateTaken, Status(0:OK, 1:WARNING, 2:CRITICAL)

Example data:

Date Interval    1    2    3    4    5    6    7    8    9    10
-------------------------------------------------------------------
Inspection #1    0    -    -    1    2    2    0    -    -    -                    
Inspection #2    2    -    -    1    0    1    -    -    -    0            
Inspection #3    0    0    0    0    0    0    0    0    0    0                   
-------------------------------------------------------------------
Worst Status     2    2    2    1    2    2    1    1    1    0    

On a chart I need to display the overall worst status over time (grouped by hour/day/week) bearing in mind that an Inspection that was CRITICAL on one reading will continue to be CRITICAL until a reading has been taken that indicates it is now OK but may not have any readings in between.

Currently, I generate a dictionary for each date interval for each Inspection for the desired timescale, bringing the last-known status forward per interval, and store them in a list:

// get readings for every point
foreach (Inspection insp in list)
{                    
    Dictionary<DateTime, int> dict = new Dictionary<DateTime, int>();

    DateTime startDate = GetStartDateFromUserSelection();                    
    var readings = insp.Readings.Where(a => a.DateTaken >= startDate).GroupBy(a => a.DateTaken.Date);

    // status to bring the previous date interval's value
    int status = 0;
    // loop, increment from start date to now daily (TODO: hourly/weekly)
    for (DateTime date = startDate; date <= DateTime.Today; date = date.AddDays(1))
    {
        // group all readings for inspection by date interval
        var dailyReadings = readings.Where(a => a.Key.Date == date.Date).FirstOrDefault();
        if (dailyReadings != null)
        {
            Reading reading = dailyReadings.OrderByDescending(a => a.Status).FirstOrDefault();
            if (reading != null)
                status = read.Status;
        }
        // status will continue to stay as last-set value until a reading resets it
        dict.Add(date, status);
    }
statusList.Add(dict);
}

Then I iterate over all the lists to find the highest reading on a particular date interval:

for (int i = 0; i < statusList[0].Count; i++)
{
    DateTime date = statusList[0].ElementAt(i).Key;
    int status = 0;
    foreach (var list in statusList)
    {
        if (list.Count > 0)
        status = list.ElementAt(i).Value > status ? list.ElementAt(i).Value : status;
    }
    worstStatus.Add(date, status);
}
chart.DataContext = worstStatus;

I know this is not the best way to do it but my logic-brain is AWOL and I need some help! How can I achieve this without so much processing?

Was it helpful?

Solution

Hopefully a more concise version (though I'm not claiming it's much faster in terms of actual processing):

var dates = Enumerable.Range(0, (DateTime.Now - startDate).Days + 1)
                      .Reverse()
                      .Select(i => DateTime.Now.Date.AddDays(-i))
                      .ToArray();

var dailyReadings =
   list.SelectMany(inspection => dates.Select(d => 
      new
      {
         Date = d,
         Reading = inspection.Readings
                             .OrderBy(r => r.DateTaken)
                             .LastOrDefault(reading => reading.DateTaken <= d) 
      }));

var worstCases =
   dailyReadings.GroupBy(dr => dr.Date)
                .Select(g => new
                             {
                                Date = g.Key,
                                Status = g.Max(i => i.Reading == null
                                                     ? Status.Ok
                                                     : i.Reading.Status)
                             });
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top