两个arrays的产品总和(dotproduct)

首先,我知道我的标题可以更好地表达,但我的数学课程已经不复存在了,我不记得正确的单词了。

我需要做这样的事情(伪c#)

int[] digits1 = new int[10]{0,1,2,3,4,5,6,7,8,9}; int[] digits2 = new int[10]{0,1,2,3,4,5,6,7,8,9}; int result = digits1*digits2 

这将是每个数组的元素[i]的乘积之和。

这显然不起作用。 对任何更好的头衔或解决方案的任何建议?

编辑澄清:我知道我可以循环它们并进行数学计算。 基本上我认为有一个更好的方法来做到这一点,我纯粹出于个人的好奇而寻找它。

使用LINQ:

 int dotProduct = digits1.Zip(digits2, (d1, d2) => d1 * d2) .Sum(); 

Zip将生成一个流序列,其中包含来自两个数组的相应元素的乘积,然后将其求和为Sum整数。

请注意,这不会像在长度不等的数组时那样失败,因此您可能需要validation输入:

 //null checks here if(digits1.Length != digits2.Length) throw new ArgumentException("..."); 

编辑:正如Jeff M指出的那样, Enumerable.Zip只被添加到.NET 4.0中的框架中。 在.NET 3.5中,您可以这样做(这个想法仅对暴露快速索引器的集合有效):

 int dotProduct = Enumerable.Range(0, digits1.Length) .Sum(i => digits1[i] * digits2[i]); //from Jeff M's comment: int dotProduct = digits1.Select((n, i) => n * digits2[i]) .Sum(); 

LINQ的解决方案

 int[] digits1 = new int[10]{0,1,2,3,4,5,6,7,8,9}; int[] digits2 = new int[10]{0,1,2,3,4,5,6,7,8,9}; int result1 = digits1.Zip(digits2, (x, y) => x * y).Sum(); int result2 = digits1.Select((x, y) => x * digits2.ElementAt(y)).Sum(); int result3 = digits1.Select((n, i) => n * digits2[i]).Sum(); // Ani answer int result4 = Enumerable.Range(0, digits1.Length) .Sum(i => digits1[i] * digits2[i]); 

性能测试 100000次迭代:

 Queries Fn: Result 1 Ticks 135306 Fn: Result 2 Ticks 2470614 Fn: Result 3 Ticks 130034 Fn: Result 4 Ticks 123374 ------------- Fastest Fn: Result 4 Ticks 123374 Fn: Result 3 Ticks 130034 Fn: Result 1 Ticks 135306 Fn: Result 2 Ticks 2470614 

很简单,做一个循环。

 int sum = 0; for(int i = 0; i < digits1.length && i < digits2.length; i++) { sum += digits1[i] * digits2[i]; } 

繁荣。

我写了一个测试台来比较这些方法在我的机器上的时间。

眼镜:
Windows 7专业版64位
英特尔酷睿2四核Q9550 @ 2.83GHz
4x1GiB Corsair Dominator DDR2 1066(PC2-8500)

 using System; using System.Linq; namespace Testbench { class Program { static void Main(string[] args) { var digits1 = Enumerable.Range(0, 500).ToArray(); var digits2 = digits1.ToArray(); // create a copy Test("Regular Loop", () => { int result = 0; for (int i = 0; i < digits1.Length; i++) { result += digits1[i] * digits2[i]; } return result; }); // using LINQ Test("Enumerable \"Loop\"", () => Enumerable.Range(0, digits1.Length).Sum(i => digits1[i] * digits2[i])); Test("Using Zip", () => digits1.Zip(digits2, (x, y) => x * y).Sum()); Test("Using Indexed Select", () => digits1.Select((n, i) => n * digits2[i]).Sum()); Test("Using Indexed Select with ElementAt", () => digits1.Select((n, i) => n * digits2.ElementAt(i)).Sum()); // using PLINQ Test("Parallel Enumerable \"Loop\"", () => ParallelEnumerable.Range(0, digits1.Length).Sum(i => digits1[i] * digits2[i])); Test("Using Parallel Zip", () => digits1.AsParallel().Zip(digits2.AsParallel(), (x, y) => x * y).Sum()); Test("Using Parallel Indexed Select", () => digits1.AsParallel().Select((n, i) => n * digits2[i]).Sum()); Test("Using Parallel Indexed Select with ElementAt", () => digits1.AsParallel().Select((n, i) => n * digits2.ElementAt(i)).Sum()); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); Console.WriteLine(); } static void Test(string testName, Func test, int iterations = 1000000) { Console.WriteLine(testName); Console.WriteLine("Iterations: {0}", iterations); var results = Enumerable.Repeat(0, iterations).Select(i => new System.Diagnostics.Stopwatch()).ToList(); var timer = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < results.Count; i++) { results[i].Start(); test(); results[i].Stop(); } timer.Stop(); Console.WriteLine("Time(ms): {0,3}/{1,10}/{2,8} ({3,10})", results.Min(t => t.ElapsedMilliseconds), results.Average(t => t.ElapsedMilliseconds), results.Max(t => t.ElapsedMilliseconds), timer.ElapsedMilliseconds); Console.WriteLine("Ticks: {0,3}/{1,10}/{2,8} ({3,10})", results.Min(t => t.ElapsedTicks), results.Average(t => t.ElapsedTicks), results.Max(t => t.ElapsedTicks), timer.ElapsedTicks); Console.WriteLine(); } } } 

32位目标:

常规循环
迭代次数:1000000
时间(毫秒):0/0/0(1172)
蜱:3 / 3.101365 / 526(3244251)

可枚举的“循环”
迭代次数:1000000
时间(毫秒):0 / 4.3E-05/25(9054)
蜱虫:24 / 24.93989 / 69441(25052172)

使用Zip
迭代次数:1000000
时间(毫秒):0 / 2.4E-05/16(16282)
蜱:41 / 44.941406 / 45395(45052491)

使用索引选择
迭代次数:1000000
时间(毫秒):0 / 5.3E-05/32(13473)
蜱:34 / 37.165088 / 89602(37280177)

使用带有ElementAt的索引选择
迭代次数:1000000
时间(毫秒):0 / 1.5E-05/6(160215)
蜱:405 / 443.154147 / 17821(443306156)

并行可枚举的“循环”
迭代次数:1000000
时间(毫秒):0 / 0.000103 / 29(17194)
蜱:38 / 47.412312 / 81906(47576133)

使用Parallel Zip
迭代次数:1000000
时间(分钟):0 / 9.4E-05/19(21703)
蜱:49 / 59.859005 / 53200(60051081)

使用平行索引选择
迭代次数:1000000
时间(分钟):0 / 0.000114 / 27(20579)
蜱:45 / 56.758491 / 75455(56943627)

使用带有ElementAt的并行索引选择
迭代次数:1000000
时间(毫秒):0 / 8.1E-05/19(61137)
蜱虫:144 / 168.97909 / 53320(169165086)

64位目标:

常规循环
迭代次数:1000000
时间(毫秒):0/0/0(506)
蜱虫:1 / 1.254137 / 1491(1401969)

可枚举的“循环”
迭代次数:1000000
时间(毫秒):0 / 2.9E-05/15(10118)
蜱:27 / 27.850086 / 41954(27995994)

使用Zip
迭代次数:1000000
时间(毫秒):0 / 2.2E-05/13(17089)
蜱:45 / 47.132834 / 38506(47284608)

使用索引选择
迭代次数:1000000
时间(毫秒):0 / 3.1E-05/12(14057)
蜱:37 / 38.740923 / 33846(38897274)

使用带有ElementAt的索引选择
迭代次数:1000000
时间(毫秒):0 / 3.8E-05/29(117412)
蜱:304 / 324.711279 / 82726(324872753)

并行可枚举的“循环”
迭代次数:1000000
时间(分钟):0 / 9.9E-05/28(24234)
蜱:38 / 66.79389 / 77578(67054956)

使用Parallel Zip
迭代次数:1000000
时间(毫秒):0 / 0.000111 / 24(30193)
蜱:46 / 83.264037 / 69029(83542711)

使用平行索引选择
迭代次数:1000000
时间(毫秒):0 / 6.5E-05/20(28417)
蜱:45 / 78.337831 / 56354(78628396)

使用带有ElementAt的并行索引选择
迭代次数:1000000
时间(毫秒):0 / 9.2E-05/16(65233)
蜱虫:112 / 180.154663 / 44799(180496754)
 int result = 0; for(int i = 0; i < digits1.length; i++) { result += digits1[i] * digits2[i]; }