Question

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

For example:
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<T> of an anonymous type, which will have two fields.

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

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

Any suggestions?

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

Was it helpful?

Solution

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);
    }
}

OTHER TIPS

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

It would 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 this:

foreach (var s in top3Subjects)
{
    Console.WriteLine("{0} : {1}", s.Key, s.Value);
}

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top