views:

74

answers:

1

Hi

Say I have this in my database

courseName : English101
Mark : 80
OutOff : 100
Weight : 50

CourseName : English101
Mark : 30
OutOff : 50
Weight : 10

CourseName: Chem101
Mark  : 100
OutOff: 100
Weight : 100

Now I want to find the over all grade for both of these courses

First english101.

(80 /100) * 50 = 40(achieved weight) (30 / 50) * 10 = 6

40 + 6 = 46 / 100(course weight always will total up to 100% - this means that 40% of the weight has not been distributed yet but still counts again the overallMark.)

so if this student would drop out of english101 their final mark would be 46%.

Now I don't know how to do this at all. At first I tried to add up all the marks, outOff and weights by using Group by and Sum functions when retrieving from the database.

However this gives different percents than what I am expecting. So I need to do it row by row.

So I have to add each row up then take all the rows say from English101 and add up their achieved weight.

But I don't how to do this. I tried to use a dictionary and use the courseName as the key and then check if the next row coming in had the same courseName. Then I would pull up the current value from that dictionary and add it to it.

But I only made it half way through of making it and I had 1 foreach loop and 3 nested if statements.

So there should be a better way.

I am using linq to sql. I am not sure I can use that to do all this while it is coming from the database.

+1  A: 

How about:

var results = from course in courses
              where course.OutOf != 0
              group course by course.CourseName into grouped
              select new { CourseName = grouped.Key,
                           Mark = grouped.Sum(item => 
                                    (item.Mark * item.Weight) / item.OutOf) };

Test in LINQ to Objects:

using System;
using System.Linq;

class Test
{
    static void Main(string[] args)
    {
        var courses = new[]
        {
            new { CourseName = "English101", Mark = 80, OutOf = 100, Weight =50},
            new { CourseName = "English101", Mark = 30, OutOf = 50, Weight = 10},
            new { CourseName = "Chem101", Mark = 100, OutOf = 100, Weight = 100 }
        };

        var results = from course in courses
              where course.OutOf != 0
              group course by course.CourseName into grouped
              select new { CourseName = grouped.Key,
                           Mark = grouped.Sum(item => 
                                    (item.Mark * item.Weight) / item.OutOf) };

        foreach (var result in results)
        {
            Console.WriteLine(result);
        }
    }
}

I don't know whether you'll need to worry about integer arithmetic and division when it's done in the database... you may not want the result of each bit of the sum to be truncated.

The fact that some rows will be missing is irrelevant, because the weight of the valid rows will still add up to the appropriate amount.

Jon Skeet
Wow I don't think i would have every thought of doing Mark * Weight / OutOf. Your a math Genuies lol. I am not sure what you mean by " don't know whether you'll need to worry about integer arithmetic and division when it's done in the database... you may not want the result of each bit of the sum to be truncated."Also I should have mentioned that I still want to grab the course prefix even if there is no overAllGrade. this seems to ingnore the courses that have nothing filled out(ie nulls in the db).
xiao
Oh another problem is since I have null values and stuff I can a divide by zero error.
xiao
To include courses with no marks, use the null coalescing operator: `item.Mark ?? 0` etc. The precision part is to avoid a problem where you add up two partial marks of (say) 12.5 but end up with 24 instead of 25 - if you do everything in integer arithmetic, you'll end up rounding down before the sum, which isn't ideal.
Jon Skeet
If you have null weights, you should probably use a conditional: `(item.Weight == 0 || item.Weight == null ? 0 : ...)`
Jon Skeet
Sorry I am not to sure how to use this coalescing operator. Could you please update your example? Mark,Weight,OutOf are all decimals in the database So I don't think I would run into this problem(correct me if I am wrong.)
xiao
If they're decimals in the database and in your model, then they won't be null by the time they get to you. Are they nullable fields in the database? If so, do they really have to be?
Jon Skeet
yes they are nullable fields. They these rows are created once a pearson creates a course task. This way I can assoicate the foriegns keys with the right primary keys.
xiao
My mistake lol they are not nullable fields(getting confused with another table). Anyways the problem is that at the time they are created the OutOff is not known so it is set to "0" you can't divide by zero so thats why I need something to skip any rows that have an outOff as zero.
xiao
But I still need to count the overall 100% weight against it.
xiao
Just add a where clause - will update.
Jon Skeet
Lol you just make it look so simple. Ya that seems to solve all my problems just one last problem of it. How can I return courses that have no total, totaled. For instance CourseName Chem101,Mark 0-0 OutOff - 0, weight(0 or set to some number).I want to still grab the courseName. Can I do this this query or does it have to be a seperate query.
xiao
I think you'd have to do that as a separate query... or at least, that would be the *simplest* thing to do.
Jon Skeet