FreeCodeCamp and JavaScript: Using reduce() and the arguments object to solve a problem

So at last, here’s the FreeCodeCamp problem I was struggling with.  It’s called Symmetric Difference.

NOTE: IF YOU HAVEN’T COMPLETED THIS – Go and try it first.  If you just copy my solution, you won’t learn anything, and when it comes time to interview, you won’t pass the coding test.

“Create a function that takes two or more arrays and returns an array of the symmetric difference (△ or ⊕) of the provided arrays.

Given two sets (for example set A = {1, 2, 3} and set B = {2, 3, 4}), the mathematical term “symmetric difference” of two sets is the set of elements which are in either of the two sets, but not in both (A △ B = C = {1, 4}). For every additional symmetric difference you take (say on a set D = {2, 3}), you should get the set with elements which are in either of the two the sets but not both (C △ D = {1, 4} △ {2, 3} = {1, 2, 3, 4}).”

Now, as I write this, I haven’t solved it, so you’re going to see my thought process (somewhat edited) in action.

So, at first glance, this looks like the problem we solved last time, Seek and Destroy.  There are some differences, though.  First, we want to keep the elements that are in either but not both, rather than just eliminating the ones in the first array and returning it.  Second, we want to compare more than two arrays in some cases.

Still, I think we can do this: Make the first array equal to a variable we’ll call compare.  You know what, I’m going to do this as pseudocode because it will be harder to understand if I don’t.  So

var compare = arguments[0];

Then we’ll use a loop:

for (var i = 1; i <arguments.length; i ++) {
}

The loop is going to cycle through the rest of the elements in arguments so we end up comparing all the arrays.  Inside the loop we’ll compare the next argument to the compare array, and create a new array that will have items that are in either but not both arrays. Well figure the code for this in a minute.  The new array will be added to on each iteration of the loop, so we need to declare it outside the loop.  We’ll continue to execute the loop until we’ve processed the last element in the arguments object.  Then we’ll return the new array which should meet the conditions of the assignment.

So, how to compare them and create the new array?  Maybe two loops, one to compare arraya to array b, and then another to compare array b to array a?

UPDATE:I solved it.  But here’s kind of what I went through in solving it.  Next time I’ll try to write while I’m solving a challenge instead of trying to remember afterwards what I did!

The first thing I did was combine all the arguments into one giant array, because I thought we wanted to eliminate ALL of the elements that ALL of the arrays had in common.  It turns out that this is not the correct answer.  Instead, you compare the first two arrays, get an answer, then compare the answer to the next array, get an answer, then compare THAT answer to the NEXT array, and so on until you’ve gone through all the arrays in arguments.

So it was back to my original plan.  Now, if you only compare the first array to the second, you’ll end up with the elements in the first array that are not in the second array as your answer.  But you won’t have the elements in the second array that aren’t in the first as part of your answer.  No problem, we’ll just compare the second array to the first…oh wait, we changed the first array already, so that won’t work!  So, what we need to do is make a copy of the first array to hold temporarily.

Oh! Sneaky JavaScript!  Creating a new variable and setting it equal to the first array means they both point to the SAME array which means when you change the first array, both variables now point to the modified array!  No good!  Indeed, when you want to make a copy of an array, you need to loop through it and copy each value in the array to the new array.

So, we run a loop and modify the first array, then run a loop and modify the second array.  Then we use the concat() method to mash them together into one array. (I covered the concat() method in a previous entry).  That array becomes the first array and we then compare it to the next array in the arguments.  We continue this loop until we hit the end of the arguments.

All done, right?  Um…no.

Looking at the answers we get back, we see that the final array we returned does indeed have all the elements that are in either but not in both, so what’s the problem?  For example, one answer we get back is:

{1, 1, 4, 5, 5}

But take a look.  How many UNIQUE numbers do you see?  There are 5 numbers, but only three unique numbers – 1, 4, 5.  And {1, 4, 5} is the right answer according to the feedback.  So what we need to do is eliminate the duplicate numbers.

So, what we’ll do is create (yet) another array, called final, that will hold all the non-duplicated numbers.  We’ll then loop through the  array with the duplicates and use the indexOf() function, which I also covered in a previous post.  What we are doing is looking to see if there is another duplicate after the number we’re looking at; if so, we ignore the number and move to the next element.  If there are no other duplicates after the number we are currently looking at, then we’ll add that number to the Final array.  This way there will only be one of each number in the Final array.

Now, we can return the Final array, which has the right answers and no duplicates, and we’re done!  Here’s the final code:

function sym(arr) {
  // Remove all the values
  var compare = arguments[0];
  var final = [];
// Do this until the last argument
  for (var count = 1; count < arguments.length; count++) {
    var args = arguments[count];
// Create a temporary copy of the first array.
    var temp = []; // A new empty array
    for (var i = 0, len = compare.length; i < len; i++) {
      temp[i] = compare[i];
    }
// Compare the first array to the second
    for (var i = 0; i < args.length; i++) {
      for (var x = compare.length; x >= 0; x–) {
        if (args[i] === compare[x]) {
          compare.splice(x, 1);
        }
      }
    }
// Compare the second array to a copy of the first
// since we’ve already modified the first array in the
// loop above.
    for (var y = 0; y < temp.length; y++) {
      for (var j = args.length; j >= 0; j–) {
        if (temp[y] === args[j]) {
          args.splice(j, 1);
        }
      }
    }
// combine the modified first array with the
// modified second array
    compare = compare.concat(args);
  }
// Get rid of the duplicates
  for (var item = 0; item < compare.length; item++) {
    var current = compare[item];
    if (final.indexOf(current) < 0) {
      final.push(current);
    }
  }
  return final;
}
sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s