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;开发者_StackOverflow中文版 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[]?".
Provided that you can use .NET 3.5 (or newer) and LINQ, try
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);
With LINQ:
arr.Sum()
An alternative also it to use the Aggregate()
extension method.
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);
});
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.
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;
}
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.
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.
精彩评论