/// <summary> /// Returns a bool and a subset of the items List, making sure the sum of all weights is close to /// desiredWeight (equal or exceeding). It the input items' sum is less than desiredWeight, /// they are upscaled to total its value. /// The returned bool is false if the values had to be rescaled, or if the total returned weight /// is not equal to desiredWeight. /// </summary> /// <param name="items"> /// A list of DOUBLE/DOUBLE tuples. Item1 contains the values, Item2 contains the respective /// weights. /// </param> /// <param name="desiredWeight">The desired sum of the resulting lists weights.</param> /// <returns></returns> public static Tuple <bool, List <Tuple <double, double> > > GetApproximateWeight(List <Tuple <double, double> > items, double desiredWeight) { double w = items.Select((Tuple <double, double> i) => i.Item2).Sum(); if (w == desiredWeight) { return(new Tuple <bool, List <Tuple <double, double> > >(true, items)); } if (w < desiredWeight) { return(new Tuple <bool, List <Tuple <double, double> > >(false, CourseCalculationHelper.Rescale(items, desiredWeight))); } w = 0.0; int j = 0; List <Tuple <double, double> > result = new List <Tuple <double, double> >(); while (w < desiredWeight) { result.Add(new Tuple <double, double>(items[j].Item1, items[j].Item2)); w += items[j].Item2; j++; } return(new Tuple <bool, List <Tuple <double, double> > >( ((w > desiredWeight) ? (false) : (true)), result )); }
/// <summary> /// Calculates the degree result based on the results from each relevant academic year. /// <para> /// This function DOES NOT interpolate missing results. /// </para> /// </summary> /// <returns>Member of Course.Degree enum</returns> public static Course.Degree Degree(List <Tuple <double, double> > yearTwo, List <Tuple <double, double> > yearThree) { double weightTwo = yearTwo.Select((Tuple <double, double> i) => i.Item2).Sum(); double weightThree = yearThree.Select((Tuple <double, double> i) => i.Item2).Sum(); if ((weightTwo < 1) || (weightThree < 1)) { throw new InvalidParameterException(); } // Rescale if weight < 120 if (weightTwo < 120) { yearTwo = CourseCalculationHelper.Rescale(yearTwo, 120); } if (weightThree < 120) { yearThree = CourseCalculationHelper.Rescale(yearThree, 120); } // Replicate modules for each 15 credits yearTwo = CourseCalculationHelper.WeightReplicatedValues(15, yearTwo).Item2; yearThree = CourseCalculationHelper.WeightReplicatedValues(15, yearThree).Item2; yearThree.Sort(CourseCalculationHelper.ValueWeightTupleSort); yearTwo.Add(yearThree[yearThree.Count - 1]); yearTwo.Sort(CourseCalculationHelper.ValueWeightTupleSort); // Get best 105 credits yearTwo = CourseCalculationHelper.GetApproximateWeight(yearTwo, 105).Item2; yearThree = CourseCalculationHelper.GetApproximateWeight(yearThree, 105).Item2; double bestLevelSix = yearThree.Average((Tuple <double, double> i) => i.Item1); double bestLevelFiveSix = yearTwo.Average((Tuple <double, double> i) => i.Item1); if ((bestLevelSix < 30) || (bestLevelFiveSix < 30)) { return(Course.Degree.Fail); } if (bestLevelSix >= 70) { if (bestLevelFiveSix >= 60) { return(Course.Degree.FirstClass); } if (bestLevelFiveSix >= 50) { return(Course.Degree.UpperSecondClass); } if (bestLevelFiveSix >= 40) { return(Course.Degree.SecondClass); } else { return(Course.Degree.ThirdClass); } } if (bestLevelSix >= 60) { if (bestLevelFiveSix >= 50) { return(Course.Degree.UpperSecondClass); } if (bestLevelFiveSix >= 40) { return(Course.Degree.SecondClass); } else { return(Course.Degree.ThirdClass); } } if (bestLevelSix >= 50) { if (bestLevelFiveSix >= 40) { return(Course.Degree.SecondClass); } else { return(Course.Degree.ThirdClass); } } if (bestLevelSix >= 40) { return(Course.Degree.ThirdClass); } return(Course.Degree.Unknown); }