Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use JavaScript to grade user response (compare two arrays)

I am working on a script to grade a user response by comparing two arrays. (It is a quiz to see how well they know information word-for-word.) I already have some of the code that I need, like making the user response lowercase and splitting it. All I need is something to find the number of differences/mistakes. For example:

var correctanswer = ["The","quick","brown","fox","jumped","over","the","lazy","dog"];
var useranswer = ["The","brown","fox","jumped","up","and","over","the","really","lazy","cat"];
alert(counterrors(correctanswer, useranswer));

In this particular example, running the function I'm looking for would return that the user made 5 errors (they omitted "quick", added "up", "and", and "really", and changed "dog" to "cat"). As you can see, the two arrays may be of different lengths.

Does anybody know how to approach this? I was thinking it would probably be a loop like:

for (x in correctanswer) {
    // compare correctanswer[x] to useranswer[x]... not sure how exactly. Seems tricky...
}

Thank you for looking at this! I have seen John Resig's diff solution (http://ejohn.org/projects/javascript-diff-algorithm/) and other similar things, and even a few array comparisons, but nothing seemed to work since the ones I found return all the differences, whereas I want to see how many differences there are. Again, thanks for looking and please let me know of any questions.

Update: Many thanks to Magnar for the answer! It worked perfectly.

like image 329
Alex Watt Avatar asked Jun 23 '11 19:06

Alex Watt


1 Answers

What you are after is the The Levenshtein Distance of the two arrays.

It is an algorithm that calculates the number of additions, deletions and substitutions necessary to transform one sequence into another.

The Wikipedia page I linked has a pseudo-code implementation. I have done a line-for-line translation to JavaScript for you:

var correctanswer = ["The","quick","brown","fox","jumped","over","the","lazy","dog"];
var useranswer =    ["The","brown","fox","jumped","up","and","over","the","really","lazy","cat"];

console.log(calculate_levenshtein_distance(correctanswer, useranswer));

function calculate_levenshtein_distance(s, t) {
  var m = s.length + 1, n = t.length + 1;
  var i, j;

  // for all i and j, d[i,j] will hold the Levenshtein distance between
  // the first i words of s and the first j words of t;
  // note that d has (m+1)x(n+1) values
  var d = [];

  for (i = 0; i < m; i++) {
    d[i] = [i]; // the distance of any first array to an empty second array
  }
  for (j = 0; j < n; j++) {
    d[0][j] = j; // the distance of any second array to an empty first array
  }

  for (j = 1; j < n; j++) {
    for (i = 1; i < m; i++) {
      if (s[i - 1] === t[j - 1]) {
        d[i][j] = d[i-1][j-1];           // no operation required
      } else {
        d[i][j] = Math.min(
                    d[i - 1][j] + 1,     // a deletion
                    d[i][j - 1] + 1,     // an insertion
                    d[i - 1][j - 1] + 1  // a substitution
                  );
      }
    }
  }

  return d[m - 1][n - 1];
}

This will log 5 to the console. Which is, as you'll see, the correct distance between the arrays. The student didn't add lazy. So it's 1 deletion, 3 additions and 1 substitutions.

like image 177
Magnar Avatar answered Sep 30 '22 11:09

Magnar