10

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?

Jacob Snyder
  • 248
  • 3
  • 7

4 Answers4

19

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.

jason
  • 236,483
  • 35
  • 423
  • 525
  • +1 good observation, but why did they make it like that, is there any reason? My be to avoid checking of overflow? – Akash Kava Jun 13 '11 at 19:03
  • 1
    @Akash: Most all C based languages have automatic promotion to `int` before any arithmetic happens. You'd probably have to go all the way back to K&R to find that one. – Billy ONeal Jun 13 '11 at 19:04
  • Not so much to avoid checking of overflow, but you can overflow very quickly with short. See: http://stackoverflow.com/questions/4343624/integer-summing-blues-short-short-problem – jason Jun 13 '11 at 19:04
5

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 ();
BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
2

The Sum extension method doesn't have an overload that takes an IEnumerable<short>.

Instead, you can pass a lambda expression that implicitly converts the shorts to ints:

short sumList = (short)numbersList.Sum(i=>i);
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
0

This confused me, but I was able to make it work like:

List<short> li = new List<short> {1,2,3,4,5};
short l = (short)li.Sum(i => i);
Joe
  • 80,724
  • 18
  • 127
  • 145