using System.Collections.Generic;
private static IEnumerable<(T item, double average)> MovingAverage<T>(
IEnumerable<T> source, Func<T, double> selector, int windowSize) {
throw new ArgumentNullException(nameof(source));
throw new ArgumentNullException(nameof(selector));
throw new ArgumentNullException(nameof(selector));
throw new ArgumentOutOfRangeException(nameof(windowSize));
var priors = new Queue<double>();
foreach (var item in source) {
double value = selector(item);
while (priors.Count > windowSize)
total -= priors.Dequeue();
if (priors.Count == windowSize)
yield return (item, total / windowSize);
public static void Main() {
(int id, char name, int value)[] data = new (int id, char name, int value)[] {
var result = string.Join(Environment.NewLine, MovingAverage(data, item => item.value, 3)
.Select(item => $"{item.item} :: {Math.Round(item.average)}"));
Console.WriteLine(result);
var max = MovingAverage(data, item => item.value, 3)
.MaxBy(pair => pair.average);
Console.WriteLine($"Max: {max.item} :: {max.average}");