如何在C#中求和一个整数数组


108

是否有比遍历数组更好的更短方法?

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

澄清:

更好的主键意味着更干净的代码,但也欢迎有关性能改进的提示。(就像已经提到的:拆分大数组)。


并不是我在寻求提高杀手级性能的方法-我只是想知道这种语法糖是否还不可用:“有String.Join-int []到底有什么用?”。


2
哪种方式更好?快点?更少的书面代码?
FredrikMörk2010年

Answers:


186

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

int sum = arr.Sum();

10
身份lambda不是必需的。除了混淆团队中的新人。

12
值得注意的是,System.OverflowException如果结果大于您可以使用带符号的32位整数(即(2 ^ 31)-1或英语〜21亿),则将产生错误。
ChrisProsser

2
int sum = arr.AsParallel().Sum();使用多个CPU内核的更快版本。要避免System.OverflowException使用long sum = arr.AsParallel().Sum(x => (long)x);,请使用HPCsharp nuget软件包
DragonSpit '19

66

就在这里。使用.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);

2
为什么会有如此复杂的3.5版之前的版本?该foreach循环在所有C#版本中均可用。
约恩·舒德罗德(JørnSchou-Rode)2010年

2
@Jørn:OP要求采用更短的方法。一个foreach刚刚替换一行代码为另一个,而不是更短。除此之外,a foreach非常好并且更具可读性。
艾哈迈德·玛吉德

2
点了。:然而,以下相比,你的样品保存18个字符foreach (int i in arr) sum += i;
约恩休乌-罗德


5

这取决于您如何定义更好。如果您希望代码看起来更简洁,则可以使用其他答案中提到的.Sum()。如果您希望该操作快速运行并且有一个大数组,则可以将其分解为多个和,然后对其求和,以使其并行。


+1在性能改进方面非常好,但老实说,我最初的愿望是摆脱迭代。
Filburt 2010年

(没有人告诉Fil,他只是将迭代向下推了几个级别)

@Will:杜德-不要指望我相信,如果我不写代码,魔术就会发生;-)
Filburt 2010年

3
我怀疑这样的并行优化必须要有一个非常大的阵列。
伊恩·默瑟

是的,因为for循环何时会成为不良习惯?
Ed S.

3

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

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

1
这似乎在Sum不起作用的地方起作用。由于某种原因,它不能在uint数组上工作,但是Aggregate可以。
John Ernest

2

如果您不喜欢LINQ,则最好使用foreach循环以避免索引不足。

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

2

对于非常大的阵列,可能需要使用不止一个机器的处理器/内核来执行计算。

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

2

上面的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,ushort和byte)的数组,对总和使用无符号long(ulong)可避免溢出异常。

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

为了更快地运行,HPCsharp nuget软件包实现了所有这些.Sum()版本以及SIMD / SSE版本和多核并行版本,从而使性能提高了许多倍。


好想法。而且,对于无符号整数数组,最好能够做ulong sum = arr.Sum(x =>(ulong)x); 但是,可悲的是,Linq .Sum()不支持无符号整数数据类型。如果需要无符号求和,则HPCsharp nuget程序包支持所有无符号数据类型。
DragonSpit

一个贡献者撤消了一个很好的想法,long sum = arr.Sum(x => (long)x);即使用Linq在C#中可以很好地工作。它为所有带符号整数数据类型的总和提供了完全准确性:sbyte,short和int。它还避免抛出溢出异常,并且非常紧凑。它不像上面的for循环那样高性能,但是并不是在所有情况下都需要性能。
DragonSpit

0

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


0

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

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

这与使用.Aggregate()扩展方法相同。
约翰·阿列克谢

-1

Theodor Zoulias漂亮的多核Parallel.ForEach实现的改进:

    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支持Interlocked.Add()。上述实现也可以轻松修改为支持其他整数和浮点数据类型,以使用CPU的多个内核并行进行求和。在HPCsharp nuget软件包中使用它。


-7

试试这个代码:

using System;

namespace Array
{
    class Program
    {
        static void Main()
        {
            int[] number = new int[] {5, 5, 6, 7};

            int sum = 0;
            for (int i = 0; i <number.Length; i++)
            {
                sum += number[i];
            }
            Console.WriteLine(sum);
        }
    }
} 

结果是:

23


您的代码不正确,必须替换Console.WriteLine(sum); 有回报 它将起作用
Abdessamad Jadid
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.