Chax
Chax

Reputation: 1061

Show average per hour in a timespan using LINQ

I have a list of Part that contains a DateTime value of when they have been registered to my Database.

I want to display how many have been registered during day shift per hour and the same per night shift.

I tried to base my logic of my general average to those two value

@{

var shiftChangeTime = new TimeSpan(16, 0, 0);
<table>
    <tr>
        @*This is my general average*@
        <td>Number of part/hour</td>
        @{
            var avg = Model.GroupBy(x => ((DateTime)x.ScanTime).TimeOfDay.Hours)
                        .Average(x => x.Count());
            <td>@(Math.Round(avg, 2))</td>
        }
    </tr>
    <tr>
        @*This is my day average*@
        <td>Number of part/hour</td>
        @{
            var avgDay = Model.GroupBy(x => ((DateTime)x.ScanTime).TimeOfDay < shiftChangeTime, y => ((DateTime)y.ScanTime).TimeOfDay.Hours)
                        .Average(x => x.Count());
            <td>@(Math.Round(avgDay, 2))</td>
        }
    </tr>
    <tr>
        @*This is my night average*@
        <td>Number of part/hour for night shift</td>
        @{
            var avgNight = Model.GroupBy(x => ((DateTime)x.ScanTime).TimeOfDay > shiftChangeTime, y => ((DateTime)y.ScanTime).TimeOfDay.Hours)
                        .Average(x => x.Count());
            <td>@(Math.Round(avgNight, 2))</td>
        }
    </tr>
</table>
}

I'm currently stuck with the logic of separating the day/night shift on an hour basis.

For now it split my total number in two.

Any idea on how to proceed?

Upvotes: 2

Views: 635

Answers (1)

Gilad Green
Gilad Green

Reputation: 37299

The problem with your code above is that after GroupBy of day/night shifts you also need to group by the Hour in order to do an hourly average.

This gives you the average of parts in an hour during day/night shifts:

List<Part> Model = new List<Part>
{
    new Part{ ScanTime = new DateTime(2016,1,1,1,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,4,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,4,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,4,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,4,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,7,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,12, 0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,17,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,19,0,0) },
    new Part{ ScanTime = new DateTime(2016,1,1,23,0,0) },
};

var shiftChangeTime = new TimeSpan(12, 0, 0);

var result = Model.GroupBy(x => x.ScanTime.TimeOfDay < shiftChangeTime ? "Day" : "Night")
     .Select(g => new
     {
         Shift = g.Key,
         Average = g.GroupBy(item => item.ScanTime.Hour, 
                             (key, group) => new { Hour = key, Amount = group.Count() })
                    .Average(y => y.Amount)
     }).ToList();

Another option if you don't want 2 GroupBy is first use Where to keep only records of specific shift and then the rest:

var dayAverage = Model.Where(x => x.ScanTime.TimeOfDay < shiftChangeTime)
                      .GroupBy(item => item.ScanTime.Hour, 
                               (key, group) => new { Hour = key, Amount = group.Count() })
                      .Average(y => y.Amount);

Upvotes: 1

Related Questions