如何在 C # 中求整数数组的总和

有没有比在数组上迭代更短的 好多了方法?

int[] arr = new int[] { 1, 2, 3 };
int sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}

澄清:

更好的主代码意味着更清晰的代码,但也欢迎有关性能改进的提示(如前所述: 拆分大型数组)。


这并不是说我在寻找杀手级的性能改进——我只是想知道这种类型的 语法糖是否已经可用: “ There’s String。加入—— int []怎么了?”.

371900 次浏览

如果您可以使用.NET 3.5(或更新版本)和 LINQ,请尝试

int sum = arr.Sum();

是的。 .NET 3.5:

int sum = arr.Sum();
Console.WriteLine(sum);

如果你不使用.NET 3.5,你可以这样做:

int sum = 0;
Array.ForEach(arr, delegate(int i) { sum += i; });
Console.WriteLine(sum);

和 LINQ 一起:

arr.Sum()

这取决于你如何更好地定义。如果希望代码看起来更干净,可以使用。其他答案中提到的和()。如果希望操作快速运行并且有一个大数组,可以将其分成子和,然后对结果进行求和,从而使其并行。

使用 foreach 的代码会更短,但是在 JIT 优化识别 for 循环控制表达式中与 Llength 的比较之后,可能会在运行时执行完全相同的步骤。

如果您不喜欢 LINQ,那么最好使用 foreach 循环来避免超出 index。

int[] arr = new int[] { 1, 2, 3 };
int sum = 0;
foreach (var item in arr)
{
sum += item;
}

在我使用的一个应用程序中:

public class ClassBlock
{
public int[] p;
public int Sum
{
get { int s = 0;  Array.ForEach(p, delegate (int i) { s += i; }); return s; }
}
}

上面 for 循环解决方案的一个问题是,对于下面的输入数组,所有正值的和结果都是负的:

int[] arr = new int[] { Int32.MaxValue, 1 };
int sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
Console.WriteLine(sum);

总和为 -2147483648,因为正结果对于 int 数据类型来说太大,并且溢出为负值。

对于相同的输入数组,arr. Sum ()建议会引发溢出异常。

一个更健壮的解决方案是对“ sum”使用更大的数据类型,如本例中的“ long”,如下所示:

int[] arr = new int[] { Int32.MaxValue, 1 };
long sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}

同样的改进适用于其他整数数据类型的求和,例如 short 和 sbyte。对于无符号整数数据类型(如 uint、 usshort 和 byte)的数组,使用无符号 long (ulong)表示和可避免溢出异常。

For 循环解决方案也比 Linq.Sum ()快很多倍

为了运行得更快,HPCSharp nuget 包实现了所有这些。Sum ()版本以及 SIMD/SSE 版本和多核并行版本,性能提高了许多倍。

另外它还可以使用 Aggregate()扩展方法。

var sum = arr.Aggregate((temp, x) => temp+x);

对于极大的数组,使用机器的多个处理器/核心执行计算可能会获得回报。

long sum = 0;
var options = new ParallelOptions()
{ MaxDegreeOfParallelism = Environment.ProcessorCount };
Parallel.ForEach(Partitioner.Create(0, arr.Length), options, range =>
{
long localSum = 0;
for (int i = range.Item1; i < range.Item2; i++)
{
localSum += arr[i];
}
Interlocked.Add(ref sum, localSum);
});

对 Theodor Zoulias 漂亮的多核并行程序的改进。每个实现:

    public static ulong SumToUlongPar(this uint[] arrayToSum, int startIndex, int length, int degreeOfParallelism = 0)
{
var concurrentSums = new ConcurrentBag<ulong>();


int maxDegreeOfPar = degreeOfParallelism <= 0 ? Environment.ProcessorCount : degreeOfParallelism;
var options = new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfPar };


Parallel.ForEach(Partitioner.Create(startIndex, startIndex + length), options, range =>
{
ulong localSum = 0;
for (int i = range.Item1; i < range.Item2; i++)
localSum += arrayToSum[i];
concurrentSums.Add(localSum);
});


ulong sum = 0;
var sumsArray = concurrentSums.ToArray();
for (int i = 0; i < sumsArray.Length; i++)
sum += sumsArray[i];


return sum;
}

它适用于无符号整数数据类型,因为 C # 只支持互锁。在 int 和 long 中添加()。上述实现也可以很容易地修改,以支持其他整数和浮点数据类型,使用 CPU 的多个核并行进行求和。它被用在 HPCSharp 的金刚石封装中。