private void applyAlgorithm(OrderAlgorithm alg)
        {
            // Get the year from the combobox on the fly
            if (cmbYears.SelectedIndex != -1)
            {
                int year = int.Parse(cmbYears.SelectedItem.ToString()); // Parse (as opposed to TryParse) is acceptable in this case since it's pre-defined safe input.

                // Get all students in that year using a simple LINQ query
                List <Student> students = (from studentsdb in App.db.Students
                                           where studentsdb.StudentYear == year
                                           select studentsdb).ToList();

                // Now for the algorithms
                switch (alg)
                {
                case OrderAlgorithm.BEST_AVERAGE:
                    // Get every student's average first of all. We do this by going through each pupil individually, calculating the average, and then putting them into a list of KVPs.
                    List <KeyValuePair <int, Student> > averages = new List <KeyValuePair <int, Student> >();

                    // Loop students
                    foreach (Student student in students)
                    {
                        // Calculate total & max totals
                        int total    = 0;
                        int maxTotal = 0;

                        // Loop their results & add them to the totals.
                        // We ONLY want to check tests from their _CURRENT_ year (not their last year), so we filter that!
                        foreach (TestResult result in student.TestResults.Where(x => x.Test.TestYear == student.StudentYear))
                        {
                            total    += result.Score.Value;
                            maxTotal += result.MaxScore;
                        }

                        // If a student only sat tests which were out of ten, and another sat one test out of 100, then the second may have an average 5 times higher while getting a score
                        //  which is much lower proportionately (i.e. 8/10 average is better than 50/100) so we convert it to a fraction of 100 to make it fairer.

                        // First, get the fraction of the maxTotal achieved:
                        // Being careful to avoid div 0 errors.
                        double frTotal;
                        if (maxTotal > 0)
                        {
                            frTotal = (double)(total) / (double)(maxTotal);
                        }
                        else
                        {
                            frTotal = 0;
                        }

                        int average = (int)(frTotal * 100);

                        // Insert into the list
                        averages.Add(new KeyValuePair <int, Student>(average, student));
                    }

                    // They are now fully loaded, so sort them:
                    averages.Sort((x, y) => y.Key.CompareTo(x.Key));

                    // And display them!
                    lstStudents.ItemsSource = averages;

                    break;

                case OrderAlgorithm.BEST_IMPROVEMENT:

                    // The algorithm for most improved will compare the gradient of their improvement based on the first, and last, half of their tests.

                    // To do this, the following steps will be followed:

                    // 1. Get their relevant tests
                    // 2. Order by date
                    // 3. Get a percentage value for each one
                    // 4. Get the average percentage for the first and second halves
                    // 5. If the second percentage is bigger than the first, we take the difference

                    List <KeyValuePair <int, Student> > differences = new List <KeyValuePair <int, Student> >();

                    foreach (Student student in students)
                    {
                        List <int> studentAverages = new List <int>();
                        // Step 1 & Step 2 //
                        // First, filter by the year group they're in. We don't want to conserve bias from the last year.   We then order by the date it began.
                        foreach (TestResult result in student.TestResults.Where(x => x.Test.TestYear == student.StudentYear).OrderBy(x => x.Test.TestBegin))
                        {
                            // Step 3 //
                            // Get the percentage in this test, as usual being careful against division by 0 errors
                            if (result.MaxScore != 0)
                            {
                                studentAverages.Add(result.Percentage);
                            }
                        }

                        if (studentAverages.Count() > 1)
                        {
                            // Step 4 //
                            int        half       = (studentAverages.Count() / 2);
                            List <int> firstHalf  = studentAverages.GetRange(0, half);
                            List <int> secondHalf = studentAverages.GetRange(half, studentAverages.Count() - half);

                            int firstHalfAvg  = 0;
                            int secondHalfAvg = 0;

                            // Total them to the total percentages (i.e. in ten tests, between 0% and 1000%)
                            firstHalf.ForEach(x => firstHalfAvg   += x);
                            secondHalf.ForEach(x => secondHalfAvg += x);

                            // And divide it down to the number of tests, so 0% -> 0% and 1000% -> 100%, and 500% -> 50% for ten tests.
                            firstHalfAvg  /= firstHalf.Count;
                            secondHalfAvg /= secondHalf.Count;

                            // Step 5 //
                            if (secondHalfAvg > firstHalfAvg)
                            {
                                differences.Add(new KeyValuePair <int, Student>(secondHalfAvg - firstHalfAvg, student));
                            }
                        }
                    }

                    // Finally, sory and show in list
                    differences.Sort((x, y) => y.Key.CompareTo(x.Key));
                    lstStudents.ItemsSource = differences;

                    break;

                case OrderAlgorithm.BEST_LOWEST:
                    // Get every student's lowest value. Similar to the implementation of average but with less math.
                    List <KeyValuePair <int, Student> > lowests = new List <KeyValuePair <int, Student> >();

                    // Loop students
                    foreach (Student student in students)
                    {
                        // Set it to the biggest number so the first number is lower no matter what (We'll assume there isn't more than 2^30 questions)
                        int lowest = int.MaxValue;

                        // Loop their results & add them to the totals. Once again, we filter the non-this year tests.
                        foreach (TestResult result in student.TestResults.Where(x => x.Test.TestYear == student.StudentYear))
                        {
                            if (result.Score < lowest)
                            {
                                lowest = result.Score.Value;
                            }
                        }

                        // Insert into the list
                        // We don't insert if their max was still "int.MaxValue" since that implies they didn't sit any tests (?)
                        if (lowest != int.MaxValue)
                        {
                            lowests.Add(new KeyValuePair <int, Student>(lowest, student));
                        }
                    }

                    // They are now fully loaded, so sort them:
                    lowests.Sort((x, y) => y.Key.CompareTo(x.Key));

                    // And display them!
                    lstStudents.ItemsSource = lowests;

                    break;
                }
            }
            // Don't throw a message as since there is a selection by default it seems unlikely this can happen, so an error is unnecessary. It should be obvious enough, anyway.
        }
 private void btnBestLowest_Click(object sender, RoutedEventArgs e)
 {
     algorithm = OrderAlgorithm.BEST_LOWEST;
 }
 private void btnBestAvg_Click(object sender, RoutedEventArgs e)
 {
     algorithm = OrderAlgorithm.BEST_AVERAGE;
 }
 private void btnBestImprv_Click(object sender, RoutedEventArgs e)
 {
     algorithm = OrderAlgorithm.BEST_IMPROVEMENT;
 }
Ejemplo n.º 5
0
 public void StartTests()
 {
     clientOrderAlgorithm = client.GetOrderAlgorithm(MSFT);
     client.SetOrderAlgorithm(MSFT, new MockOrderAlgorithm());
 }