FLUTTER / DART LISTS - How can you check if a sequence of elements contained in a list exists in the same order in another list?

I am working on a vocabulary quiz app (French to English / English to French). I need to check if what user types is what is expected. Example : "Une machine à laver" --> Expected answer is "A washing machine". The user can make many different sorts of mistakes such as spelling : "A watching machine", a word order mistake : "A machine washing" or a total mistake "A garden tool".

I have managed to deal with the checking when the expected word is just one word : "un jardin : a garden".

But with compound words, the issue of words order comes up. I split the Strings into two lists : _expectedAnswer contains the different elements of the answer : [washing,machine] _typedAnswer contains the different elements of what the user typed : [machine, washing] or [watching,machine] or [washing,machine], or [a,washing,machine] (Here, the user added an article before the noun, which shouldn't be seen as a mistake).

At the end, the algorithm must tell the user what type of mistakes he has done :

  1. Word order mistake.
  2. Word order is correct, but one or all elements contain spelling problems.
  3. word order mistake + spelling problems
  4. completely wrong.

For the spelling check I use the levenstein algorithm. And it is satisfactory.

So first I thought I should check if _typedAnswer contains all the elements of _expectedAnswer. -> Should check if the sequence of elements is the same : the order is OK, and no spelling pb.

-> Elements are all present but sequence is not respected : Problem with word order, no spelling mistakes.

-> Elements are not present --> Then we check if "similar elements" are present (which would indicate user made a spelling mistake) .... and check the order of elements too...

Any advice to help me work out this algorithm ?

I have read a lot about all the functions linked to dart lists, but I have to admit, that I kinda got lost on which one would be pertinent to use...


Solution 1:

I took the the last hour to solve your problem. I made it easy for you to test it and understand what is the logic behind it.

In order to use it in your code you have to put the control-flow statements into a separate function and pass the list of user input elements as well as the list of expected result elements to it.

For BOTH lists you need each word as a String, which is trimmed from all whitespaces!

I believe you are able to do that part, as described in your question already. I would deeply appreciate if you can upvote for my effort and accept the answer, if it helped you out.

EDIT: Requires an official dart package on pub.dev

Add a line like this to your package's pubspec.yaml:
dependencies:
  collection: ^1.15.0

Here is the logic, please copy & test in inside DartPad:

import 'package:collection/collection.dart';

void main() {
    
  List expectedAnswer = ["one", "two", "three"];
  List listWrongSpelling = ["oe", "two", "three"];
  List listWrongSpellings = ["oe", "twoo", "three"];
  List listWrongOrder = ["two", "one", "three"];
  List listEntirelyWrong = ["dskfrm", "twhoo", "111", "tedsf"];
  List listIdentical = ["one", "two", "three"];
   
  // FYI: Checks if there is any kind of mistake (is used below dynamically)
  Function eq = const ListEquality().equals;
   
  final result1 = eq(expectedAnswer, listWrongSpelling);  // false
  final result2 = eq(expectedAnswer, listWrongSpellings); // false
  final result3 = eq(expectedAnswer, listWrongOrder);     // false
  final result4 = eq(expectedAnswer, listEntirelyWrong);  // false
  final result5 = eq(expectedAnswer, listIdentical);      // true, the perfect answer
  
  // print(result1);
  // print(result2);
  // print(result3);
  // print(result4);
  // print(result5);
  
  
  // CHECK IF ANSWER IS PERFECT:
  bool isPerfect(List toBeChecked, List expectedResult) {
    Function eq = const ListEquality().equals;
    return eq(toBeChecked, expectedResult) ? true : false;
  }
    
  // ONLY EXECUTE OTHERS IF THERE IS AN MISTAKE:
  
  // Checks for word order mistake
  // Condition: Must contain each element with identical value, hence only order can be wrong
  bool checkOrder(List toBeChecked, List expectedElements) {
    List<bool> listOfResults = [];
    
    for (var element in toBeChecked)
    {
      bool result = expectedElements.contains(element);
      listOfResults.add(result);
    }
    
    // If one element is not in expectedElements return false
    return listOfResults.contains(false) ? false : true;
    
  }
  
  // Checks for any spelling errors
  
  bool checkSpelling(List toBeChecked, List expectedElements) {
    // Once this function gets executed there are only two errors possible:
    // 1st: Unexpected elements (e.g. an article) (and possibly spelling errors) >> return false
    // 2nd: No unexpected elements BUT spelling errors >> return true
    
    return toBeChecked.length == expectedElements.length ? true : false;
  }
  
  // FINAL RESULT
  String finalResult = "";
  
  // Please try out the other lists from above for all possible cases!
  bool isPerfectAnswer = isPerfect(listIdentical, expectedAnswer); 
  bool isWordOrderIncorrect = checkOrder(listIdentical, expectedAnswer); 
  bool isSpellingIncorrect = checkSpelling(listIdentical, expectedAnswer);
 
  if(isPerfectAnswer) {
   // The user entered the correct solution perfectly 
   finalResult = "Everything is correct!";
    
  } else if(isWordOrderIncorrect) {
    // CHECKS IF ONLY WORD ORDER IS WRONG
    // false means there are unexpected elements in the user input
    // true there are no unexpected elements, but the order is not correct, since the first check failed!
    // Is true the case, then both lists contain the same elements.

    finalResult = "Your word order is incorrect!";
    
  } else if(isSpellingIncorrect) {
    // Either unexpected elements (lenght of lists must differ) OR misspelled (same length, error in spelling)
    finalResult = "Your spelling is incorrect!";    
  } else {
    // If it gets here, the input has:
    // Unexpected elements (e.g. an article), possibly spelling errors AND possibly order mistakes 
    
    // You could check if the order is correct, but what´s the point to write complex logic for that,
    // knowing there are also unexpected elements, like additional prepositions or wrong words, in addition
    // to spelling mistakes.
    
    // Just show your user a message like this:
    finalResult = "Unfortunatelly your answer is incorrect. Try again!";   
  }
    
  // PRINT RESULT:
  print(finalResult); 
}