Home > OS >  How to compare the elements of two string lists in C# and see if any element is convertible to doubl
How to compare the elements of two string lists in C# and see if any element is convertible to doubl

Time:12-16

Hello I'm making a quiz app and I want to compare user answers to the correct answers. I'm planning to do that with two string lists as I collect the answers in strings and I also have the correct answers in strings.

The problem that I'm facing is that half of the questions are True/False questions so the answers are in "True" or "False" strings, the other half are questions where a calculation has to be performed, therefore the answer is a number/double which I store as a string.

I want to give a range of answer acceptance of 0.1 so if the correct answer is 22.5 an answer of 22.6 would still be considered correct. This, however, makes it impossible to compare the value of the "number" strings with the Equals() method.

So I'm ideally looking for an if statement where I want to say:

if the element is convertible to a double convert it and check if its value is the same as the correct answer or within the acceptance range

else, check if the element is equal to the correct answer

For now I have made a console app to try and solve this problem where I have defined the two lists which look like this:

        static void Main(string[] args)
    {
        List<string> givenAnswers = new List<string>()
        {
            "True","False","True","False","True",
            "60","50","2.321","0.8","1.55"
        };

        List<string> correctAnswers = new List<string>()
        {
            "True","False","False","True","False",
            "70","20","1.231","0.5","1.25"
        };

        correctAnswers.ForEach(Console.WriteLine);

        Console.ReadLine();

    }

The main problem is that c# doesnt return false if the element is not convertible but gives error which breaks the program.

(I was previously making the comparison on my frontend - java script where an unsuccessful conversion would return false)

CodePudding user response:

Let's extract a method to compare two answers:

private static bool IsCorrectAnswer(string answer, 
                                    string expectedAnswer, 
                                    double tolerance = 0.1) {
  // Let's not be peevish and tolerate leading / trimming spaces,
  // ignore cases i.e. let " TRUE  " be equal to "True"
  if (string.Equals(answer?.Trim(), 
      expectedAnswer?.Trim(), 
      StringComparison.OrdinalIgnoreCase))
    return true;

  // If we have two double values, let's to parse them and compare 
  // with provided tolerance
  if (double.TryParse(answer, out var leftValue) && 
      double.TryParse(expectedAnswer, out var rightValue))
    return Math.Abs(leftValue - rightValue) <= tolerance;

    //TODO: you may want to add support for other types (say, dates) here

  return false;
}

CodePudding user response:

I didn't get your string list of booleans and numbers, but the general check would look like this:

foreach (var answer in givenAnswers)
{
  if (double.TryParse(answer, NumberStyles.Any, CultureInfo.InvariantCulture, out double answerVal) && answerVal == 0.8)
  {
    Console.WriteLine("Nailed it!");
  }
}

I had to use "invariant culture" because in my country, 0.8 is written as "0,8" and thus "0.8" is parses to 8...

I wouldn't go into lengths about the "nearby" numbers, because it's very complicated. Comparing Floating Point Numbers, 2012 Edition

CodePudding user response:

var convertible = int.TryParse("60", out_)

CodePudding user response:

You can use double.TryParse to check if a string is parsable to a double and parse it at the same time when it is.

bool IsAcceptableAnswser(string givenAnswer, string correctAnswer)
{
  if (double.TryParse(correctAnswer, out var correctNumber) && double.TryParse(givenAnswer, out var givenNumber))
  {
    // When the answers are doubles, use use the double values.
    var diff = Math.Abs(correctNumber - givenNumber);
    return diff <= 0.1;  
  }
  else
  {
    // When the answers aren't doubles, use string.Equals.
    return string.Equals(givenAnswer, correctAnswer);
  }

Notes

  • I used string.Equals for simplicity, but you could of course use something else to be more permissive around casing.
  • You might also want to check the other overloads of double.TryParse if culture is an issue.
  • I used 0.1 directly for readability. It would be preferable to use a constant or receive it as parameter.
  • Related