views:

70

answers:

4

Hi folks,

I have a simple POCO class that contains the student's scores.

eg.
Math - 83%
Engrish - 82%
Chemistry - 81%
Drama - 100%
etc..

Is there a way (using linq?) that i could figure out the top 3 properties ordered by score? I'm assuming the final object will be an IList of an anonymous type, which will have two fields.

  1. Name (the name of the property)
  2. Score (the decimal value).

The number of proprties in the object ARE finite though :)

Any suggestions?

As an alternative answer, could this be done in a database instead?

cheers :)

+3  A: 

Are you looking for something like this?

class Notes
{
    public double Math{ get; set; }
    public double English { get; set; }
    public double Chemistry { get; set; }
    public double Drama { get; set; }
    public string IgnoreMePlease { get; set; }
}

class Program
{
    static void PrintHighestNotes(Notes notes)
    {
        var pairs = from property in notes.GetType().GetProperties()
                     where property.PropertyType == typeof (double)
                     select new
                            {
                                Name = property.Name,
                                Value = (double) property.GetValue(notes, null)
                            };
        var result = pairs.OrderByDescending(pair => pair.Value);

        foreach (var pair in result)
            Console.WriteLine("{0} = {1}", pair.Name, pair.Value);
    }

    static void Main(string[] args)
    {
        Notes notes = new Notes()
                      {
                          Chemistry = 0.10,
                          Math = 0.2,
                          Drama = 1,
                          English = 0.3,
                          IgnoreMePlease = "Ignore"
                      };
        PrintHighestNotes(notes);
    }
}
maciejkow
I ended up calling .ToDictionary :) simple :)
Pure.Krome
A: 

It's not clear in your question if the scores are all separate properties or if they're some kind of list. If they're a list, this would work:

 var topScores =
    (from s in Scores
    orderby s.Score descending
    select new { s.Name, s.Score}).Take(3);
Jon Galloway
Hi Jon. I'm sure i mentioned that they are seperate properties. So appologies if I didn't communicate the appropriately. Thanks for the answer though :) (and I lub linq) :)
Pure.Krome
+1  A: 

Unless you already happen to have all the data in memory, it's more efficient to let the database select the correct data for you.

If you store the grades as fields in the database, you have to normalise it to make it possible to query. The best is to redesign the database and put the grades as rows in a separate table. The data should be in the fields of the tables, not as field names:

select top 3 GradeName, Grade
from Grades
where StudentId = 42
order by Grade desc

You can also normalise the data on the fly, but that is of course not nearly as efficient:

select top 3 GradeName, Grade
from (
   select GradeName = 'Engrish', Grade = Engrish from Students where StudentId = 42
   union all
   select 'Drama', Drama from Students where StudentId = 42
   union all
   select 'Math', Math from Students where StudentId = 42
   union all
   select 'Chemistry', Chemistry from Students where StudentId = 42
) Grades
order by Grade desc
Guffa
I also like the use of doing this in a DB.
Pure.Krome
+1  A: 

Wouldn't it be simpler to use a dictionary with the subject as the key and the score as the value ?

Dictionary<string, int> scores = new Dictionary<string, int>();
...

var top3Subjects = (from s in scores
                  orderby s.Value descending
                  select s).Take(3);

This returns an IEnumerable<KeyValuePair<string, int>>, which you can use like that :

foreach (var s in top3Subjects)
{
    Console.WriteLine("{0} : {1}", s.Key, s.Value);
}
Thomas Levesque
actually, that's not a bad suggestion. And it's nice and simple :)
Pure.Krome