Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ aggregate functions on bytes, shorts, and unsigned values

Tags:

c#

linq

How would you go about using LINQ aggregate functions (ex. Sum, Average) on collections of bytes, shorts, and unsigned values? Granted, I'm a new C# programmer, but I can't even figure out how to get something that compiles let alone has proper output.

Here's a trivial example of what I am trying to do:

short[] numbersArray = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
short sumArray = numbersArray.Sum();

or

List<short> numbersList = new List<short> { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
short sumList = numbersList.Sum();

I can't either of these samples to work. If I change the data type to int it works, but I can't get it to work for shorts, bytes, uints, etc.

What am I doing wrong?

like image 242
Jacob Snyder Avatar asked Jun 13 '11 18:06

Jacob Snyder


2 Answers

Enumerable.Sum<T>() is only defined for IEnumerable<T> where T in

double,
double?
int,
int?
decimal,
decimal?
long,
long?
float,
float?

This is because there is no addition operator* for short or any of the other primitive types (short + short is int, for example).

You have to say:

short[] numbersArray = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int sumArray = numbersArray.Sum(x => (int)x);

and less explicitly you can get away with

short[] numbersArray = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int sumArray = numbersArray.Sum(x => x);

In this case, you are now invoking the overload:

int Enumerable.Sum<short>(
    this IEnumerable<short> source,
    Func<short, int> selector
)

*: Here I mean "operator" in the sense of an function F:(short x short) -> short.

like image 100
jason Avatar answered Nov 12 '22 04:11

jason


Enumerable.Sum accepts either ints, longs, singles or doubles.

You can cast the numbers to make them eligible as the parameter:

short [] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int sum = numbers.Cast<int> ().Sum ();

As an alternative, you can provide a Func<TSource, int> lambda that selects ints for you:

short [] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int sum = numbers.Sum (x => x); // lambda type is inferred as Func<short, int>

I declare sum as int because it's really unsafe to think a sum of shorts is a short itself.
It is even reflected in the fact that you have to do explicit casting when adding shorts:

int sum = a + b; 
short shortSum = (short)(a + b); // you can use an explicit casting to get short

So if you're certain you're not going to overflow, just cast the result:

short shortSum = (short) numbers.Cast<int> ().Sum ();
like image 5
Dan Abramov Avatar answered Nov 12 '22 02:11

Dan Abramov