0

Please review my brief example code below and tell me if there is better, tighter way to write the LINQ query. The parent class is simply a student's name and a list of test score data. The child class is a single test score datum. I want to find the worst (or best) score out of all of the TestScore values and then identify the student who had the best score.

Thanks!

Dim query = From s In studentList _
            Where s.ScoreList.Select(Function(d) d.TestScore).Min _
                = studentList.SelectMany(Function(g) g.ScoreList).Select(Function(h) h.TestScore).Min _
            Select StudentName = s.Student, _
                   WorstScore = s.ScoreList.Select(Function(g) g.TestScore).Min
BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
blueshift
  • 831
  • 2
  • 12
  • 24

3 Answers3

2

I'm not a VB person so there may be some syntax errors, but I can suggest two improvements:

  • Rather than using Select then Min, use the overload of Min which accepts a projection
  • Don't find the overall minimum on every iteration; just do it once:

    Dim worstScore = studentList.SelectMany(Function(g) g.ScoreList) _
                                .Min(Function(h) h.TestScore)
    
    Dim query = From s In studentList _
                Where s.ScoreList.Min(Function(d) d.TestScore) = worstScore
                Select s.Student
    

Note that I've removed the anonymous type from the query - we know the worstScore already, so we don't really need it in with the query result. Note that there could still be multiple students with that worst score though.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I prefer your answer because it removes the redundant data (worstScore) from the query. Thanks for pointing out the Min projection. – blueshift Apr 21 '11 at 12:56
1

How about

Dim query = studentList.OrderBy(Function(d) d.ScoreList.Select(Function(d) d.TestScore).Min).First()

Using OrderByDescending and Max to find the best score.

BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
0

The first thing I would do if I were you is add a MinimumScore and MaximumScore property to StudentScores make AddScore keep track of the minimum and maximum score that you've seen so far. Now for a given student you can find these in O(1) time instead of in O(n) time

Then what you want to do is write an implementation of MaxBy and MinBy. I don't speak VB fluently, but you can find an implementation of MaxBy in C# in a previous answer and convert to VB accordingly.

Finally, having done all this, you can say

studentWithBestScore = studentList.MaxBy(s => s.MaximumScore);
var bestScore = studentWithBestScore.MaximumScore;

(Again, you'll have to convert this to VB.)

Community
  • 1
  • 1
jason
  • 236,483
  • 35
  • 423
  • 525
  • Thanks for taking time to respond. The MaxBy and MinBy might be useful to me at another time. For now, I'll pursue an approach that uses native LINQ syntax. – blueshift Apr 21 '11 at 12:59