我有多个Float
的输入数组,它们的大小和大小相同。我想创建一个包含所有输入数组平均值的输出数组。
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]
我还想计算输入数组的标准偏差。
执行此任务的最快方法是什么?
提前致谢。 皮特
答案 0 :(得分:8)
本文详细介绍了如何使用LINQ实现目标,以最大的可重用性和多功能性为主要目标。
取1(为方便起见,将LINQ打包成方法)
采取这种方法:
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();
}
它的工作原理是获取范围[0..arrays.Length-1]
,并且对于范围内的每个数字i
,它计算每个数组的i
元素的平均值。它可以非常方便地使用:
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);
这可以在任何数量的阵列上使用而无需修改。但是你可以再迈一步,做一些更普遍的事情。
取2(对任何聚合函数进行推广)
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();
}
这可用于计算任何聚合函数:
var output = ArrayAggregate(Enumerable.Average, array1, array2, array3, array4);
而不是Enumerable.Average
你可以替换任何方法,扩展方法或匿名函数 - 这是有用的,因为没有内置的标准偏差聚合函数,这样ArrayAggregate
函数是非常多才多艺。但我们仍然可以做得更好。
取3(对任何聚合函数和任何类型的数组进行推广)
我们还可以制作适用于任何内置类型的通用版本:
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();
}
正如您可能已经知道的那样,这不是执行此工作的最快代码。如果您的计划花费全天计算平均值,请使用更接近金属的东西。但是,如果你想要可重用性和多功能性,我认为你不能比上面做得更好。
答案 1 :(得分:4)
性能方面最快的方法,除非你想展开for循环
float[] sums = new float[4];
for(int i = 0; i < 4; i++)
{
sums[i] = (array1[i]+ array2[i] + array3[i] + array4[i])/4;
}
答案 2 :(得分:0)
static void Main()
{
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 };
float[] avg = CrossAverage (array1, array2, array3, array4);
Console.WriteLine (string.Join ("|", avg.Select(f => f.ToString ()).ToArray()));
}
private static float[] CrossAverage (params float [][] arrays)
{
int [] count = new int [arrays[0].Length];
float [] sum = new float [arrays[0].Length];
for (int j = 0; j < arrays.Length; j++)
{
for (int i = 0; i < count.Length; i++)
{
count[i] ++;
sum[i] += arrays[j][i];
}
}
float [] avg = new float [arrays[0].Length];
for (int i = 0; i < count.Length; i++)
{
avg[i] = sum[i] / count[i];
}
return avg;
}
不要忘记边界检查并除以0检查。
答案 3 :(得分:0)
对于计算平均值(进入和数组)后的标准偏差:
// std dev
float[] stddevs = new float[4];
for (int i = 0; i < 4; i++)
{
stddevs[i] += (array1[i] - sums[i]) * (array1[i] - sums[i]);
stddevs[i] += (array2[i] - sums[i]) * (array2[i] - sums[i]);
stddevs[i] += (array3[i] - sums[i]) * (array3[i] - sums[i]);
stddevs[i] += (array4[i] - sums[i]) * (array4[i] - sums[i]);
}
for (int i = 0; i < 4; i++)
stddevs[i] = (float)Math.Sqrt(stddevs[i]/4);
通常,由于允许编译器/ JIT进行优化,因此直接访问数组而不是使用LINQ将获得性能提升。至少,可以消除数组边界检查,并避免使用枚举器的开销。