Search code examples
c#linq

Get averages for each day of week with LINQ


I'm new to C# and This is the first time I'm using LINQ queries. I have a Dictionary as Dictionary<(int MeterId, DateTime TimeStamp), float> With data as follows,

<(10411, 12/1/2022 12:30:00 AM), 5700>
<(10411, 13/1/2022 12:30:00 AM), 5200>
<(10412, 12/1/2022 12:30:00 AM), 200>

Then there's a method to add them to a list with meterId and average value for each day of week. I'm using LINQ queries to calculate the averages and get them to a list.

        public static List<AveragedMeter> CalculateAverageValues(Dictionary<(int MeterId, DateTime TimeStamp), float> groupedMeterValues)
        {
            var lstResult = groupedMeterValues
                .GroupBy(m => new { m.Key.MeterId, m.Key.TimeStamp.DayOfWeek })
                .Select(g => new AveragedMeter
                {
                    MeterId = g.Key.MeterId,
                    AverageMondayValue,
                    AverageTuesdayValue,
                    AverageWednesdayValue,
                    AverageThursdayValue,
                    AverageFridayValue,
                    AverageSaturdayValue,
                    AverageSundayValue
                })
                .ToList();

            return lstResult;
        }

I'm not certain how to get for these average values. My AveragedMeter class is as follows,

    class AveragedMeter
    {
        public int MeterId { get; set; }
        public float AverageMondayValue { get; set; }
        public float AverageTuesdayValue { get; set; }
        public float AverageWednesdayValue { get; set; }
        public float AverageThursdayValue { get; set; }
        public float AverageFridayValue { get; set; }
        public float AverageSaturdayValue { get; set; }
        public float AverageSundayValue { get; set; }
    }

Solution

  • The accepted the answer is not performance optimal because it iterates all values 7 times (excluding the GroupBy()). I propose a solution the iterates the values only twice:

    static List<AveragedMeter> CalculateAverageValues(
        Dictionary<(int MeterId, DateTime TimeStamp), float> groupedMeterValues)
        => groupedMeterValues
            .GroupBy(g => g.Key.MeterId)
            .Select(g => CalculateAverageDays(
                g.Key,
                g.ToLookup(x => x.Key.TimeStamp.DayOfWeek, x => x.Value)))
            .ToList();
    
    static AveragedMeter CalculateAverageDays(
        int meterId,
        ILookup<DayOfWeek, float> valuesPerDay)
        => new AveragedMeter {
            MeterId = meterId,
            AverageMondayValue = valuesPerDay[DayOfWeek.Monday].DefaultIfEmpty().Average(),
            AverageTuesdayValue = valuesPerDay[DayOfWeek.Tuesday].DefaultIfEmpty().Average(),
            AverageWednesdayValue = valuesPerDay[DayOfWeek.Wednesday].DefaultIfEmpty().Average(),
            AverageThursdayValue = valuesPerDay[DayOfWeek.Thursday].DefaultIfEmpty().Average(),
            AverageFridayValue = valuesPerDay[DayOfWeek.Friday].DefaultIfEmpty().Average(),
            AverageSaturdayValue = valuesPerDay[DayOfWeek.Saturday].DefaultIfEmpty().Average(),
            AverageSundayValue = valuesPerDay[DayOfWeek.Sunday].DefaultIfEmpty().Average()
        };