3

I am relatively new to C# and newer to LINQ. I haven't found a good way to do this using LINQ (meaning an example on here that does almost exactly this, lol), but it seems like there should be a way to eliminate one of my loops.

I have a 2D List of List. I want to make a 2D List of averaged chunks of data of each of the sub Lists.

Example input:

averageSize = 2

input List = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}

expected output List:

{{1.5,3.5}, {5.5,7.5}, {9.5, 11.5}}

I have working code with a foreach loop and a for loop. waveData is the input 2D list, averageSize is the number of values to average together

            int tempIndex = 0;
        List<List<double>> averages = new List<List<double>>();
        foreach (List<double> phaseData in waveData)
        {
            averages.Add(new List<double> { });
            for (int i = 0; i <= (phaseData.Count-averageSize); i+= averageSize)
            {
                averages[tempIndex].Add(phaseData.GetRange(i, averageSize).Average());
            }
            tempIndex++;
        }
abatishchev
  • 98,240
  • 88
  • 296
  • 433
db28
  • 33
  • 3
  • 5
    Don't get me wrong--LINQ is pretty handy and extremely useful at times, but only when it really is the better alternative. What is better? Well, immediate understanding of what the code actually does, easy to modify when data structures change, having control over the process (LINQ can get 'optimized' by the compiler). IMHO: your code looks fine. If it works, then I see no reason to go to LINQ...in this case. Just saying... – Barns May 14 '20 at 19:06
  • 1
    You can have a look at existing solutions in this question [Split List into Sublists with LINQ](https://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq) – Pavel Anikhouski May 14 '20 at 20:35

1 Answers1

1

Batch extension method from MoreLINQ package is exactly what you need. It takes the source enumerable and divides it into batches of given size. Resulting LINQ expression will look like this:

public List<List<double>> CalculateBatchAverages(List<List<double>> data, int batchSize = 2)
{
    return data.Select(list => list
            .Batch(batchSize)
            .Select(batch => batch.Average())
            .ToList())
        .ToList();
}
  • 1
    MoreLINQ - Nice Library. Looks very extensive. And easy to implement. Just have to weight to advantages of use--against the (sometimes) pain of integrating third party libraries. – Barns May 14 '20 at 19:28
  • @Barns - you can also use any of the equivalents to `Batch()` from [Split List into Sublists with LINQ](https://stackoverflow.com/q/419019/3744182). Your question is almost but not quite a duplicate of that question, since you have the additional `Average()` step. – dbc May 14 '20 at 22:34
  • This does what I wanted. After testing, the for loop I originally had was faster for the dataset sizes I will be using so I think I will be sticking with that. Thanks! – db28 May 18 '20 at 16:53