Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fastest way to create Average array from multiple arrays of numbers

Tags:

arrays

c#

I have multiple input arrays of Float all of equal size and a single dimension. I want to create a single output Array that contains the average of all the input arrays.

e.g.

//input arrays
float[] array1 = new float[] { 1, 1, 1, 1 };
float[] array2 = new float[] { 2, 2, 2, 2 };
float[] array3 = new float[] { 3, 3, 3, 3 };
float[] array4 = new float[] { 4, 4, 4, 4 };

//the output should be
float[2.5, 2.5, 2.5, 2.5]

I would also like to calculate the standard deviation of the input arrays to.

What is the fastest approach to do this task?

Thanks in advance. Pete

like image 774
Peter Avatar asked Jun 17 '11 23:06

Peter


2 Answers

LINQ to the rescue

This anwer details how to use LINQ to achieve the goal, with maximum reusability and versatility as the major objective.

Take 1 (package LINQ into a method for convenience)

Take this method:

float[] ArrayAverage(params float[][] arrays)
{
    // If you want to check that all arrays are the same size, something
    // like this is convenient:
    // var arrayLength = arrays.Select(a => a.Length).Distinct().Single();

    return Enumerable.Range(0, arrays[0].Length)
               .Select(i => arrays.Select(a => a.Skip(i).First()).Average())
               .ToArray();
}

It works by taking the range [0..arrays.Length-1] and for each number i in the range it calculates the average of the ith element of each array. It can be used very conveniently:

float[] array1 = new float[] { 1, 1, 1, 1 };
float[] array2 = new float[] { 2, 2, 2, 2 };
float[] array3 = new float[] { 3, 3, 3, 3 };
float[] array4 = new float[] { 4, 4, 4, 4 };

var averages = ArrayAverage(array1, array2, array3, array4);

This can already be used on any number of arrays without modification. But you can go one more step and do something more general.

Take 2 (generalizing for any aggregate function)

float[] ArrayAggregate(Func<IEnumerable<float>, float> aggregate, params float[][] arrays)
{
    return Enumerable.Range(0, arrays[0].Length)
               .Select(i => aggregate(arrays.Select(a => a.Skip(i).First())))
               .ToArray();
}

This can be used to calculate any aggregate function:

var output = ArrayAggregate(Enumerable.Average, array1, array2, array3, array4);

Instead of Enumerable.Average you can substitute any method, extension method, or anonymous function -- which is useful, as there's no built-in standard deviation aggregate function and also this way the ArrayAggregate function is very versatile. But we can still do better.

Take 3 (generalizing for any aggregate function and any type of array)

We can also make a generic version that works with any built-in type:

T[] ArrayAggregate<T>(Func<IEnumerable<T>, T> aggregate, params T[][] arrays)
{
    return Enumerable.Range(0, arrays[0].Length)
               .Select(i => aggregate(arrays.Select(a => a.Skip(i).First())))
               .ToArray();
}

As you can probably tell, this is not the fastest code to do the job. If your program spends all day calculating averages, use something more close to the metal. However, if you want reusability and versatility I don't think you can do much better than the above.

like image 134
Jon Avatar answered Oct 26 '22 13:10

Jon


The fastest way in terms of performance, unless you'd like to unroll the for loop is

float[] sums = new float[4];

for(int i = 0; i < 4; i++)
{
    sums[i] = (array1[i]+ array2[i] + array3[i] + array4[i])/4;
}
like image 36
Yuriy Faktorovich Avatar answered Oct 26 '22 14:10

Yuriy Faktorovich