146

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[]?".

Filburt
  • 17,626
  • 12
  • 64
  • 115

11 Answers11

248

Provided that you can use .NET 3.5 (or newer) and LINQ, try

int sum = arr.Sum();

Sample

int[] arr = new int[] { 1, 2, 3 };
int sum = arr.Sum();

// output = 6
Console.WriteLine(sum);
niek tuytel
  • 899
  • 7
  • 18
Tomas Vana
  • 18,317
  • 9
  • 53
  • 64
  • 15
    It is worth noting that this will get raise an error `System.OverflowException` if the result would be greater than you can fit in a signed 32 bit integer (i.e. (2^31) -1 or in english ~ 2.1 billion). – ChrisProsser Mar 14 '15 at 20:15
  • 5
    `int sum = arr.AsParallel().Sum();` a faster version that uses multiple cores of the CPU. To avoid `System.OverflowException` you can use `long sum = arr.AsParallel().Sum(x => (long)x);` For even faster versions that avoid overflow exception and support all integer data types and uses data parallel SIMD/SSE instructions, take a look at HPCsharp nuget package – DragonSpit Jul 20 '19 at 16:13
  • Is too bad performance – nim May 09 '22 at 00:09
70

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);
Ahmad Mageed
  • 94,561
  • 19
  • 163
  • 174
  • 2
    Why such a convoluted pre 3.5 version? The `foreach` loop is available in all versions of C#. – Jørn Schou-Rode Mar 16 '10 at 09:37
  • 2
    @Jørn: the OP asked for a shorter approach. A `foreach` just substitutes one line of code for another and isn't shorter. Apart from that a `foreach` is perfectly fine and is more readable. – Ahmad Mageed Mar 16 '10 at 11:34
  • 2
    Point taken. Yet, the following saves 18 chars compared to your sample: `foreach (int i in arr) sum += i;` – Jørn Schou-Rode Mar 16 '10 at 11:44
23

With LINQ:

arr.Sum()
Chris
  • 3,664
  • 6
  • 34
  • 44
6

An alternative also it to use the Aggregate() extension method.

var sum = arr.Aggregate((temp, x) => temp+x);
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • 2
    This seems to work where Sum doesn’t. It wouldn’t work on an array of uint for some reason but Aggregate would. – John Ernest Jul 08 '20 at 23:21
5

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.

unholysampler
  • 17,141
  • 7
  • 47
  • 64
4

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);
});
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
3

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.

DragonSpit
  • 458
  • 4
  • 9
  • Great idea. And, for unsigned integer array it would be nice to be able to do ulong sum = arr.Sum(x => (ulong)x); But, sadly, Linq .Sum() doesn't support unsigned integer data types. If unsigned summation is needed, HPCsharp nuget package supports it for all unsigned data types. – DragonSpit Jun 17 '19 at 01:42
  • A contributor withdrew a nice idea of `long sum = arr.Sum(x => (long)x);` which works nicely in C# using Linq. It provides the full accuracy for the summation for all signed integer data types: sbyte, short, and int. It also avoids throwing an overflow exception, and is nicely compact. It's not as high performance as the for loop above, but performance is not needed in all cases. – DragonSpit Jun 22 '19 at 15:54
2

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;
}
HENG Vongkol
  • 883
  • 1
  • 8
  • 10
0

Using foreach would be shorter code, but probably do exactly the same steps at runtime after JIT optimization recognizes the comparison to Length in the for-loop controlling expression.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

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; }
    }
}
merrais
  • 371
  • 2
  • 9
0

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.

DragonSpit
  • 458
  • 4
  • 9