Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

C# Querying With LINQ Querying the BirdWatcher Data How Much Data Do We Have?

Daniel Breen
Daniel Breen
14,943 Points

Select vs SelectMany When Getting Average

With the following code in mind...

var sightingsCorrect = birds.SelectMany(b => b.Sightings).Count();  // 1817
var sightingsWrong = birds.Select(b => b.Sightings).Count();  // 201
var average = birds.Select(b => b.Sightings.Count()).Average();      // 9.03980099502488

Note that sightingsCorrect uses SelectMany(), while sightingsWrong and average use Select().

Why don't we use SelectMany to get the average? How does Linq bring back the correct average? I would assume that average would be 1 (201 / 201 = 1)

1 Answer

Steven Parker
Steven Parker
231,269 Points

These variable names are a bit confusing, "sightingsCorrect" is actually the total number of sightings, and "sightingsWrong " is just a count of birds. It could be written more simply without the "Select" as:

var sightingsWrong = birds.Count();  // 201

The reason the average works is that the "Count" is applied to the sightings for each bird. So the "Average" totals them up and then divides by the number of counts. You can't use "SelectMany" there because it works on lists, not individual values as the "Count" returns.

Daniel Breen
Daniel Breen
14,943 Points

var sightingsWrong = birds.Select(b => b.Sightings).Count(); is actually not a count of birds. It's a count of unflattened Sightings lists, which happens to be equal to the count of birds. That's what I've been trying to figure out. :) I don't understand how birds.Select(b => b.Sightings.Count()).Average(); is expanding (unflattening?) Sightings without using SelectMany to count each item in Sightings before averaging.

Steven Parker
Steven Parker
231,269 Points

When I said "count of birds", I meant that it "happens to be equal to the count of birds". So it makes sense to use the simpler method and just count birds since you get the same result.

The reason you don't need (and can't use) "SelectMany" with "Average" is because "b.Sightings.Count()" converts each list into a single number, eliminating the need for "flattening". Then those single numbers get averaged.

You _can_use flattening to compute an average, and that is also shown in the video, but you do the math yourself instead of using the "Average" method:

var averageSightings = birds.SelectMany(b => b.Sightings).Count() / birds.Count();  // 9