Reputation: 239
_.filter = function(collection, test) {
var result = [];
_.each(collection, function(value) {
if(test(value)) {
result.push(value);
}
})
return result;
};
_.reject = function(collection, test) {
var result = [];
return _.filter(collection, function(value) {
return !test(value);
})
};
I'm a bit puzzled by how this works. I have two underscore.js functions defined here in the same scope. If I pass a test array of random nums how does _.filter in _.reject work?
var isEven = function(num) { return num % 2 === 0; };
var odds = _.reject([1, 2, 3, 4, 5, 6], isEven);
expect(odds).to.eql([1, 3, 5]);
For example I test my functions and I get the assert is true but I don't understand how this works
Upvotes: 0
Views: 154
Reputation: 50684
For example, if your array of numbers are:
const nums = [1, 2, 3, 4, 5, 6]
and you have a function isEven
which takes a number and returns true
if it is even and false
if it is not even (ie odd):
function isEven(num) {
return num % 2 === 0;
}
Then running _.filter(arr, isEven)
will perform the following logic:
arr
takes the name of collection
and isEven
takes the name of test
result
.Loop through every number in even
value
), check if calling test(value)
gives a result of true
. test(value)
is true, then add the number (value
) to the end of the result
array.collection
return the result
array.
So, filter()
executes the isEven
function for each number in your array, and if it returns true
, it is added to a new array (ie: it is kept).
_.reject()
does the opposite to _.filter()
- that is, it keeps all elements the callback function returns false
for. As you know _.filter()
keeps values it returns true
for, you can use _.filter()
by negating the value of the boolean returned by test(value)
. This way, when test(value)
returns false
, you negate it to be true
, making the _.filter()
method keep that element. If test(value)
returns true
, then you will negate that to be false
, making the filter method discard of that value
.
Upvotes: 1
Reputation: 40002
Reject is just reusing some logic that filter accomplishes. It could easily have been written this way:
_.reject = function(collection, test) {
var result = [];
_.each(collection, function(value) {
if(!test(value)) {
result.push(value);
}
})
return result;
};
You will notice that the only thing difference between filter and reject is whether we want to keep items when the test is true, or when the test is false.
// Creates the function reject
_.reject = function(collection, test) {
var result = [];
// Calls filter but hands in a custom callback.
// Filter iterates each item in the list, and keeps it
// if test(item) returns true (test is our custom flipResult).
// Remember that reject does the opposite, it keeps it
// if test(item) returns false (aka !true).
return _.filter(collection, function flipResult(value) {
// The user gave us a test method. We want to keep items
// that return false when passed to test.
// If we call _.filter(collection, test) we will get all
// items that return true when passed to test, but thats not what we want
// So instead of handing test in directly, we hand in our custom callback
// The custom callback calls test and flips the result.
// This means filter will keep all items that return false
// because our custom callback is flipping the result !test
return !test(value);
})
};
Upvotes: 1