Careful with those lambdas, sonny

Well, sonny is me, actually.

I spent quite a long time trying to understand why my LINQ average function wasn’t working.

Paring down to a simple example, I wanted to check the average of a filtered subset of data.

Say my data is an array if integers:

int[] nums = { 84, 123, 101, 94, 238 };

I can get the average of these by calling:

var numavg=nums.Average();  –returns 128.0

I then wanted to get the average of only those numbers that were greater than 100.

But wait, I really started this in VB! So I was writing this function:

Dim avgnums = mynums.Average(Function(n) n > 100)

Which compiled and ran, but returned -0.333333333333.

I looked at it inside and out, over and under and could not figure out what was going on.

so then I tried it in C# and got this compiler error:

Cannot convert lambda expression to delegate type ‘System.Func<int,int>’ because some of the return types in the block are not implicitly convertible to the delegate return type 

Finally I noticed the other error listed in the Errors window:

Cannot implicitly convert type ‘bool’ to ‘int’

And realized the error of my ways.

I was thinking that my lambda was for filtering, but all I was doing was an eval which was returning trues and falses depending on whether the value was >100 or not. And the average function was the same as Average(0,0,0,0,-1,-1) which is -2/6. So -0.333333333 was correct!

[note – Option Strict was off which imacted this – see additional comments at the end of this post]

So what is the correct way to do what I wanted? I need a filtering method, duh!

in C#:

var numavg3 = nums.Where(q => q > 100).Average();

in VB

Dim avgnums2 = mynums.Where(Function(n) n > 100).Average(Function(n) n)

About VB’s Option Strict in this example

As Bill McCarthy points out, Option Strict=On would have caught the attempt to use a boolean in the Average function, forcing me to specifiy the types in the array, which I *had* in fact done in the C# code, (because it forced me to). Option Strict is one of those things you need to change to “ON” after you install Visual Studio. I had missed it in this installation and because I was focused on what I was doing wrong with the lambdas, it hadn’t even occurred to me.

Dim mynums() As Integer = {10, 20, 40, 100, 120, 140}

Otherwise, he compiler tells you: “Option Strict on requires all variable declarations to have an ‘As’ clause.” Which is a lie. There are cases where it is required and cases where it is not. Note my VB code for calculating the average is still valid and avgnums2 is recognized as a Double at compile time.

On the other hand, VB’s implicit casting is still in play as is demonstrated by then taking that double and concatenating it with a string.

 Dim x = avgnums2 & “xya”

  Sign up for my newsletter so you don't miss my conference & Pluralsight course announcements!  

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.