Pages

Monday, June 6, 2016

Rebuilding Underscore's reject function

While filter returns a new array of items from the original array that pass a truth test, reject returns ones that don't pass the truth test.

While one could start from scratch re writing everything, it would be better to note that filter nearly does the same thing.  Can't one just fiddle with filter a bit?  Since we're calling reject here, we can't reach inside filter and fiddle, but what we can fiddle with is the function that we feed reject, but that same function is going to be fed to filter, and that's where the fiddling happens.

First, let's run reject one time:


console.log(_.reject([1,2,3,4,6,8], function(item){
  return item % 2 === 0;
}););

Look familiar?  If we fed the same test to filter we would get [2,4,6,8], but with reject we will get [1,3]

Reject will need filter and each in order to run, so I'll paste those in below here first:

  _.each =  function(collection, iterator){

  if(Array.isArray(collection)){
    for(var i = 0; i < collection.length; i ++){
      iterator(collection[i], i, collection);
    }
  }
  else{
    for(var key in collection){
      iterator(collection[key], key, collection);
    }
  }
}



_.filter = function(collection, test) {
  var filterArray = [];

  _.each(collection, function(item){
    if(test(item)){
      filterArray.push(item);
    }
  });
  return filterArray;
}



_.reject = function(collection, test) {
    return  _.filter(collection, function(item){
      return !test(item);
    })

}


So, the reject function calls filter, and it feeds filter the collection, and then hard wires in a function for filter.  The function given to filter says to return the value of the test (this is the function we give reject when we call reject) with item as the argument and the bang sign tells it to turn true into false and false into true.

If you need to see an example of how this works, try this out in the console, or repl.it :

(8 % 2) === 0     This will equate to true.

!(8 % 2) === 0    This will equate to false.

So, take a look at where the filter function is written above.  Filter calls each, and then each takes the test with item as a parameter.  It runs this function which will either return true or false.  If it returns true then it pushes that item to the new array, where it waits to be returned at the end of the function.

So, when we hard wire our function to filter inside our reject function, we are giving the test that will be passed to each, that's why this function has access to item.  However, where it would normally return true, it will not return false because of our bang sign.  And where it would normally return false, it will now return true.

This is why all the items that fail the test will be returned, instead of all those that pass it.








No comments:

Post a Comment