-1

e.g. We have a collection

[ 
  {1,' A,' 100},
  {2, 'X', 200},
  {3, 'D', 300},
  {5, 'B', 300},
  {6, 'Z', 300},
  {7, 'G', 300}, 
]

likewise.

I start with the last object first then If my limit is 3 then I'll pick the last three to find the average of int num.

In this 1, 2, 3 then 2, 3, 4 but 4 is missing from the collection then I will skip this and pick 3, 4, 5 same I need to skip this finally I will start 5, 6, 7 wise I will go N record.

Then I need to pick a set that contains the highest average of the number.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Murtuza
  • 73
  • 1
  • 8

1 Answers1

1

Are you looking for a moving average? Having a window of size == 3 you compute averages of 0..2 items, then of 1..3 items, etc:

  (1, 'A', 100), -> not enough data to compute moving average
  (2, 'X', 200), -> not enough data to compute moving average
  (3, 'D', 300), -> (100 + 200 + 300) / 3 == 200
  (5, 'B', 300), -> (200 + 300 + 300) / 3 == 267
  (6, 'Z', 300), -> (300 + 300 + 300) / 3 == 300
  (7, 'G', 300), -> (300 + 300 + 300) / 3 == 300

If it's your task, then you can do it as follow:

  private static IEnumerable<(T item, double average)> MovingAverage<T>(
    IEnumerable<T> source, Func<T, double> selector, int windowSize) {

    if (source is null)
      throw new ArgumentNullException(nameof(source));
    if (selector is null)
      throw new ArgumentNullException(nameof(selector));
    if (selector is null)
      throw new ArgumentNullException(nameof(selector));
    if (windowSize <= 0)
      throw new ArgumentOutOfRangeException(nameof(windowSize));

    double total = 0.0;
    var priors = new Queue<double>();

    foreach (var item in source) {
      double value = selector(item);
      priors.Enqueue(value);
      total += value;   
  
      while (priors.Count > windowSize)
        total -= priors.Dequeue();

      if (priors.Count == windowSize)    
        yield return (item, total / windowSize);
    }
  } 

Demo:

var data = new (int id, char name, int value)[] { 
  (1, 'A', 100),
  (2, 'X', 200),
  (3, 'D', 300),
  (5, 'B', 300),
  (6, 'Z', 300),
  (7, 'G', 300),
};
      
var result = string.Join(Environment.NewLine, 
   MovingAverage(data, item => item.value, 3)
  .Select(item => $"{item.item} :: {Math.Round(item.average)}"));

Console.Write(result);

Output:

(3, D, 300) :: 200   // (100 + 200 + 300) / 3
(5, B, 300) :: 267   // (200 + 300 + 300) / 3
(6, Z, 300) :: 300   // (300 + 300 + 300) / 3
(7, G, 300) :: 300   // (300 + 300 + 300) / 3

Having moving average computed, you can easily obtain max record from it with a help of Linq:

    using System.Linq;

    ...

    var max = MovingAverage(data, item => item.value, 3)
      .MaxBy(pair => pair.average);   
        
    Console.WriteLine($"Max: {max.item} :: {max.average}");   

Output:

Max: (6, Z, 300) :: 300

which means that max moving average (that is 300) group starts from (6, Z, 300) item.

Fiddle

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215