Sum of products of two arrays (dotproduct) Sum of products of two arrays (dotproduct) arrays arrays

Sum of products of two arrays (dotproduct)


With LINQ:

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

Zipwill produce a streaming sequence containing the products of corresponding elements from both arrays, which is then summed into an integer with Sum.

Note that this will not fail like it should when the arrays of unequal length, so you probably need to validate the input:

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

EDIT:As Jeff M points out,Enumerable.Zipwas only added to the framework in .NET 4.0. In .NET 3.5, you can do this (the idea is only efficient for collections that expose fast indexers):

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


Solutions with 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 answerint result4 = Enumerable.Range(0, digits1.Length)    .Sum(i => digits1[i] * digits2[i]);

Performance test 100000 iterations:

QueriesFn: Result 1       Ticks 135306Fn: Result 2       Ticks 2470614Fn: Result 3       Ticks 130034Fn: Result 4       Ticks 123374-------------FastestFn: Result 4       Ticks 123374Fn: Result 3       Ticks 130034Fn: Result 1       Ticks 135306Fn: Result 2       Ticks 2470614


I wrote a test bench to compare the these methods' times on my machine.

Specs:
Windows 7 Professional 64-bit
Intel Core 2 Quad 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<T>(string testName, Func<T> 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-bit target:

Regular LoopIterations: 1000000Time(ms):   0/         0/       0 (      1172)Ticks:      3/  3.101365/     526 (   3244251)Enumerable "Loop"Iterations: 1000000Time(ms):   0/   4.3E-05/      25 (      9054)Ticks:     24/  24.93989/   69441 (  25052172)Using ZipIterations: 1000000Time(ms):   0/   2.4E-05/      16 (     16282)Ticks:     41/ 44.941406/   45395 (  45052491)Using Indexed SelectIterations: 1000000Time(ms):   0/   5.3E-05/      32 (     13473)Ticks:     34/ 37.165088/   89602 (  37280177)Using Indexed Select with ElementAtIterations: 1000000Time(ms):   0/   1.5E-05/       6 (    160215)Ticks:    405/443.154147/   17821 ( 443306156)Parallel Enumerable "Loop"Iterations: 1000000Time(ms):   0/  0.000103/      29 (     17194)Ticks:     38/ 47.412312/   81906 (  47576133)Using Parallel ZipIterations: 1000000Time(ms):   0/   9.4E-05/      19 (     21703)Ticks:     49/ 59.859005/   53200 (  60051081)Using Parallel Indexed SelectIterations: 1000000Time(ms):   0/  0.000114/      27 (     20579)Ticks:     45/ 56.758491/   75455 (  56943627)Using Parallel Indexed Select with ElementAtIterations: 1000000Time(ms):   0/   8.1E-05/      19 (     61137)Ticks:    144/ 168.97909/   53320 ( 169165086)

64-bit target:

Regular LoopIterations: 1000000Time(ms):   0/         0/       0 (       506)Ticks:      1/  1.254137/    1491 (   1401969)Enumerable "Loop"Iterations: 1000000Time(ms):   0/   2.9E-05/      15 (     10118)Ticks:     27/ 27.850086/   41954 (  27995994)Using ZipIterations: 1000000Time(ms):   0/   2.2E-05/      13 (     17089)Ticks:     45/ 47.132834/   38506 (  47284608)Using Indexed SelectIterations: 1000000Time(ms):   0/   3.1E-05/      12 (     14057)Ticks:     37/ 38.740923/   33846 (  38897274)Using Indexed Select with ElementAtIterations: 1000000Time(ms):   0/   3.8E-05/      29 (    117412)Ticks:    304/324.711279/   82726 ( 324872753)Parallel Enumerable "Loop"Iterations: 1000000Time(ms):   0/   9.9E-05/      28 (     24234)Ticks:     38/  66.79389/   77578 (  67054956)Using Parallel ZipIterations: 1000000Time(ms):   0/  0.000111/      24 (     30193)Ticks:     46/ 83.264037/   69029 (  83542711)Using Parallel Indexed SelectIterations: 1000000Time(ms):   0/   6.5E-05/      20 (     28417)Ticks:     45/ 78.337831/   56354 (  78628396)Using Parallel Indexed Select with ElementAtIterations: 1000000Time(ms):   0/   9.2E-05/      16 (     65233)Ticks:    112/180.154663/   44799 ( 180496754)