简体   繁体   中英

How to sum up an array of integers in C#

Is there a better shorter way than iterating over the array?

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

clarification:

Better primary means cleaner code but hints on performance improvement are also welcome. (Like already mentioned: splitting large arrays).


It's not like I was looking for killer performance improvement - I just wondered if this very kind of syntactic sugar wasn't already available: "There's String.Join - what the heck about int[]?".

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

int sum = arr.Sum();

Yes there is. With .NET 3.5:

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

If you're not using .NET 3.5 you could do this:

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

使用 LINQ:

arr.Sum()

另一种方法是使用Aggregate()扩展方法。

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

It depends on how you define better. If you want the code to look cleaner, you can use .Sum() as mentioned in other answers. If you want the operation to run quickly and you have a large array, you can make it parallel by breaking it into sub sums and then sum the results.

For extremely large arrays it may pay off to perform the calculation using more than one processors/cores of the machine.

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);
});

If you don't prefer LINQ, it is better to use foreach loop to avoid out of index.

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

One problem with the for loop solutions above is that for the following input array with all positive values, the sum result is negative:

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

The sum is -2147483648, as the positive result is too big for the int data type and overflows into a negative value.

For the same input array the arr.Sum() suggestions cause an overflow exception to be thrown.

A more robust solution is to use a larger data type, such as a "long" in this case, for the "sum" as follows:

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

The same improvement works for summation of other integer data types, such as short, and sbyte. For arrays of unsigned integer data types such as uint, ushort and byte, using an unsigned long (ulong) for the sum avoids the overflow exception.

The for loop solution is also many times faster than Linq .Sum()

To run even faster, HPCsharp nuget package implements all of these .Sum() versions as well as SIMD/SSE versions and multi-core parallel ones, for many times faster performance.

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

In one of my apps I used :

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

An improvement on Theodor Zoulias's nice multi-core Parallel.ForEach implementation:

    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;
    }

which works for unsigned integer data types, since C# only support Interlocked.Add() for int and long. The above implementation can also be easily modified to support other integer and floating-point data types to do summation in parallel using multiple cores of the CPU. It is used in the HPCsharp nuget package.

Is there a better shorter way than iterating over the array?

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

clarification:

Better primary means cleaner code but hints on performance improvement are also welcome. (Like already mentioned: splitting large arrays).


It's not like I was looking for killer performance improvement - I just wondered if this very kind of syntactic sugar wasn't already available: "There's String.Join - what the heck about int[]?".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM