Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant averaging of arrays from different instances of an object in C#

I have a list of objects of the same type that each has a property that is an array of floats. Taking this list as input, what is the easiest way to return a new array that is the average of the arrays in the list?

The input objects look like this:

Class MyDatas
{
    float [] DataValues;
}

...

List<MyDatas> InputList;
float [] result;

The DataValues arrays will be guaranteed to have the same length. Each element of the result array will be the average of the corresponding elements in the array of each member of the list. For example: result[0] = (InputList[0].DataValues[0] + InputList[1].DataValues[0] + ... ) / InputList.Count

Of course I could brute force this with a foreach inside a for loop and then another for loop after that but it seems to me this should be doable with one or two lines of LINQ. Any advice?

like image 545
Segfault Avatar asked Jul 12 '11 18:07

Segfault


2 Answers

float[] result = inputList.Select(c => c.DataValues)
                          .Transpose()
                          .Select(r => r.Average())
                          .ToArray();

using Transpose from here.

like image 145
dtb Avatar answered Nov 15 '22 05:11

dtb


Pure LINQ:

var result = InputList
    .SelectMany(x => x.DataValues.Select((y, i) => new { y, i }))
    .GroupBy(a => a.i, b => b.y, (k, v) => v.Average());

Sample:

List<MyDatas> InputList = new List<MyDatas>();
InputList.Add(new MyDatas { DataValues = new float[] { 1, 2, 3 } });
InputList.Add(new MyDatas { DataValues = new float[] { 4, 5, 6 } });
InputList.Add(new MyDatas { DataValues = new float[] { 7, 8, 9 } });

var result = InputList
    .SelectMany(x => x.DataValues.Select((y, i) => new { y, i }))
    .GroupBy(a => a.i, b => b.y, (k, v) => v.Average());


foreach (var item in result)
{
    Console.WriteLine(item);
}

Output:

4
5
6
like image 31
Kirill Polishchuk Avatar answered Nov 15 '22 06:11

Kirill Polishchuk