private (PracticeResult bestResult, PracticeResult worstResult) EvaluatePartialResults(string[] results, string[] inputs) { var bestResult = PracticeResult.Wrong; var worstResult = PracticeResult.Correct; foreach (string result in results) { var bestMatch = PracticeResult.Wrong; foreach (string input in inputs) { PracticeResult match = EvaluateOptionalExpressions(result, input); if (match != PracticeResult.Correct) { string[] partialResults = result.SplitAndTrim(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); string[] partialInputs = input.SplitAndTrim(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); // If the synonym contains separators which match with the input in term of count // we evaluate each part of the input as a synonym and check if we get a better score if (partialResults.Length == partialInputs.Length && partialResults.Length > 1) { (_, PracticeResult partialMatch) = EvaluatePartialResults(partialResults, partialInputs); if (partialMatch > match) { match = partialMatch; } } } if (match > bestMatch) { bestMatch = match; } } if (bestMatch > bestResult) { bestResult = bestMatch; } if (bestMatch < worstResult) { worstResult = bestMatch; } } return(bestResult, worstResult); }
public async Task <List <PracticeData> > GetPracticeData(int runnerid) { var practicedata = new List <PracticeData>(); //Get times by runner var listoftimes = await TimeServices.GetListOfTimesbyRunnerId(runnerid); //Creates list of dates Dictionary <int, DateTime> eventdates = new Dictionary <int, DateTime>(); //Select times from a events var practices = listoftimes.GroupBy(ev => new { ev.EventId }).Select(grp => grp.First()).ToList(); foreach (var practice in practices) { var tmpevent = await EventServices.GetEventById(practice.EventId.GetValueOrDefault()); //if event is a race remove form the list of races if (tmpevent.IsRace) { listoftimes.RemoveAll(e => e.EventId == practice.EventId.GetValueOrDefault()); } else //if event is not a race creates a dictionary with Key the event Id and content the race date to use later { eventdates.Add(tmpevent.Id, tmpevent.RaceDate); } } //creates PracticeData var grouprun = listoftimes.GroupBy(d => d.Distance).ToList(); foreach (var group in grouprun) { var practiceresults = new List <PracticeResult>(); foreach (var run in group) { var practiceresult = new PracticeResult { MaxTime = run.Times.TotalMilliseconds, MinTime = run.Times.TotalMilliseconds, Date = eventdates[run.EventId.GetValueOrDefault()] }; practiceresults.Add(practiceresult); } //Select the lower and higher times if there is more than one for a given distance i n a day var tmpresults = practiceresults.GroupBy(d => d.Date).ToList(); foreach (var date in tmpresults) { if (date.Count() > 1) { var maxtime = date.Max(t => t.MaxTime); var mintime = date.Min(t => t.MaxTime); var practiceresult = new PracticeResult { Date = date.Key, MaxTime = maxtime, MinTime = mintime }; //erase the various entries with same date and distance practiceresults.RemoveAll(d => d.Date == date.Key); //add a single entry with the maxtime and mintime of the day practiceresults.Add(practiceresult); } } //Add practices results to each distance var practice = new PracticeData { Distance = group.Key, PracticeResults = practiceresults }; practicedata.Add(practice); } return(practicedata); }
public void TestOptionalEdgeCases(PracticeResult expected, string result, string input) { Assert.AreEqual(expected, evaluator.GetResult(new[] { result }, new[] { input })); }
private PracticeResult EvaluateOptionalExpressions(string result, string input) { if (!OptionalExpressions) { return(EvaluateToleratedMistakes(result, input)); } List <Segment> segments = GetSegments(result, out int optionalCount); if (segments.Count == 1) { return(EvaluateToleratedMistakes(result, input)); } // Evaluating optional expressions range by range would be efficient but difficult // because it's not possible to match result and input indices for partly correct statements. // The alternative is to compute all possible combinations which are as many as 3 to the power // of n where n is the number of optional segments. string[] candidiates = new string[(int)Math.Pow(3, optionalCount)]; int optionalIndex = -1; for (int i = 0; i < segments.Count; i++) { Segment seg = segments[i]; var variations = new string[3]; variations[0] = result.Substring(seg.Start, seg.End - seg.Start + 1); if (segments[i].Optional) { if (seg.Space == 0) { variations[1] = result.Substring(seg.Start + 1, seg.End - seg.Start - 1); } else if (seg.Space == -1) { variations[1] = ' ' + result.Substring(seg.Start + 2, seg.End - seg.Start - 2); } else if (seg.Space == 1) { variations[1] = result.Substring(seg.Start + 1, seg.End - seg.Start - 2) + ' '; } variations[2] = string.Empty; optionalIndex++; } int variationBlockLength = (int)Math.Pow(3, optionalCount - 1 - optionalIndex); for (int k = 0; k < candidiates.Length; k++) { int variation = seg.Optional ? k / variationBlockLength % 3 : 0; if (i == 0) { candidiates[k] = variations[variation]; } else { candidiates[k] += variations[variation]; } } } // Iterate through all possible candidates and return the result of the best match. PracticeResult bestMatch = PracticeResult.Wrong; foreach (string candidate in candidiates) { PracticeResult match = EvaluateToleratedMistakes(candidate, input); if (match > bestMatch) { bestMatch = match; } } return(bestMatch); }