Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ version of calculating sum product of adjacent elements in an array

Tags:

c#

.net

linq

I am looking for a way to do the following in LINQ (it is basically a sumproduct where the same array contains both operands of the product at n and n + 1 indices, obviously the array length is always 2 * n).

int[] input = { -3, 26, -2, 19, 2, 19, 3, 29, 1, 48 };

// sum product
double result = 0;
for (int i = 0; i < input.Length; i += 2)
     result += input[i] * input[i + 1];

// result = 57

// linq version of calculating resultPrice ???

How can I do this (elegantly) with LINQ?

like image 696
brakeroo Avatar asked Dec 14 '16 14:12

brakeroo


3 Answers

You can Zip the 2 sub-arrays using multiplications and then Sum them, just as you would explain the request:

int result = input.Where((x, i) => i % 2 == 0)
    .Zip(input.Skip(1).Where((x, i) => i % 2 == 0), (x, y) => x * y)
    .Sum();

If you have MoreLinq referenced you can have a cleaner solution by folding every batch of 2 items into their product and using Sum:

var res2 = input.Batch(2)
    .Select(z => z.Fold((x, y) => x * y))
    .Sum();

Or a more generic solution by using Aggregate instead of Fold:

var res2 = input
    .Batch(2)
    .Select(batch => batch.Aggregate(1, (x, y) => x * y))
    .Sum();
like image 120
Tamir Vered Avatar answered Oct 06 '22 00:10

Tamir Vered


 var result = Enumerable.Range(0, input.Length/2)
                          .Select(i => input[i*2] * input[i*2 + 1]).Sum();

This should be enough. Here example in dotNetFiddle.


This code is pretty much mirror of:

for (int i = 0; i < input.Length/2; i++)
     result += input[i*2] * input[i*2 + 1];

which is doing the exact same thing as your loop, but instead of step +2 of your loop you have step +1 and loop duration ArrayItems/2 and you make sum of elements from input[i*2] * input[i*2 + 1]

like image 43
mybirthname Avatar answered Oct 06 '22 00:10

mybirthname


You can use the overload of Select that includes the index, then group on the index divided by 2. Aggregate the values by multiplying them, and finally do a sum.

int[] input = { -3, 26, -2, 19, 2, 19, 3, 29, 1, 48 };

var result = input.Select((v, i) => new { Index = i, Value = v })
    .GroupBy(x => x.Index / 2, x => x.Value)
    .Select(g => g.Aggregate(1, (v, a) => a *= v))
    .Sum();

Console.WriteLine(result);

This will also work for more general cases where you want to sum the produce of n consecutive numbers by dividing by n instead of 2.

like image 41
juharr Avatar answered Oct 06 '22 00:10

juharr