So you have an array with some numbers, and you want take that array and produce a new one that only has the odd numbers in it.
Input: [23, 65, 98, 5]
Output: [23, 65, 5]
As discussed, can check whether a number is odd via n % 2 === 1
.
I’m going to put that in a function, a. so that it’s in plain English, b. so I don’t have to keep typing it and c because it becomes important as I generalise the logic:
function isOdd(n) {
return n % 2 === 1;
}
So, start with a loop:
let input = [23, 65, 98, 5];
let output = [];
for (let i = 0; i < input.length; i++) {
if (isOdd(input[i])) {
output.push(input[i]);
}
}
console.log(output); // logs [23, 65, 5]
I take the input array, loop over it, and if the current value is odd, push it to the output array.
That is constrained to a single array, whereas I want it to be used for any array of numbers. So I can put the logic in a function so that it can take any array of numbers:
function filterOutEvens (numbers) {
let oddNumbers = [];
for (let i = 0; i < numbers.length; i++) {
if (isOdd(numbers[i])) {
oddNumbers.push(numbers[i]);
}
}
return oddNumbers;
}
console.log(filterOutEvens([23, 65, 98, 5])); // logs [23, 65, 5]
This is the same as the previous logic, but now I can call filterOutEvens
, give it an array, and it will return a new array with only odd numbers.
That is constrained to just one operation: filtering out even numbers. What if I wanted to filter out odd numbers? I would have to write another function almost the same. Or numbers over 10. Or negative numbers. Or whatever. I’d need to write a new function every time.
isOdd
is a function that takes a number and returns true
if it’s odd and false
if it’s even.
To generalise, it is a function that takes a single value and returns true
or false
depending on some condition you define.
So what I want is a function that takes an array + this generalised function (which could be isOdd
) and apply it where isOdd
is currently defined:
for (let i = 0; i < numbers.length; i++) {
if (isTrueFunction(numbers[i])) {
oddNumbers.push(numbers[i]);
}
}
So what I want to do is this:
function filter (inputArr, isTrueFunction) {
let outputArr = []; ┃
┗━━━━━━━━━━━━━━━━━┓
for (let i = 0; i < inputArr.length; i++) { ┃
if (isTrueFunction(inputArr[i])) { ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
outputArr.push(inputArr[i]);
}
}
return outputArr;
}
I’ve changed all the names to be more generic, because now the function can filter anything, and the array can contain anything.
So to test it:
let oddNumbers = filter([23, 65, 98, 5], isOdd);
console.log(oddNumbers); // logs [23, 65, 5
Try with a different function:
function isEven (n) {
return n % 2 === 0;
}
let evenNumbers = filter([23, 65, 98, 5], isEven);
console.log(evenNumbers); // logs [98]
The function doesn’t have to be defined seperately, can just pass it straight into the filter
function, works exactly the same:
let numbersBelow50 = filter([23, 65, 98, 5], function below50 (n) {
return n < 50;
});
console.log(numbersBelow50); // logs [23, 5]
There are different ways of writing functions, some that are much more terse and are useful for this as they save a load of typing. This acts exactly the same as the above call:
let numbersBelow50 = filter([23, 65, 98, 5], (n) => n < 50);
console.log(numbersBelow50); // logs [23, 5]
In the case of the challenge, you’re being asked to attach the function to Array.prototype
. What this means is that it will be available to all arrays in your program. It is then used by chaining the function onto an array, so like [1,2,3].filter(someTrueFalseFunction)
rather than filter([1,2,3], someTrueFalseFunction)
.
There is already a function called filter
attached to Array.prototype
, and I don’t want to override that, so I’ll call this [as per the challenge] myFilter
.
I’m changing the clumsy name of isTrueFunction
to callback
, as that’s what a function in this position is commonly called (the main function runs and it “calls back” using the function that’s passed in as an argument).
Array.prototype.myFilter = function (callback) {
let outputArr = [];
for (let i = 0; i < this.length; i++) {
if (callback(this[i])) {
outputArr.push(this[i]);
}
}
return outputArr;
}
NOTE I’m skipping over why I use this
a bit – here, this
refers to the array that myFilter
is applied to, but I’m not going to get into the vagaries of it.
So to test again:
// Comparing two identical ways of defining this.
let oddNumbers;
// Passing in a externally-defined function:
function isOdd (n) {
return n % 2 === 1;
}
oddNumbers = [23, 65, 98, 5].myFilter(isOdd);
console.log(oddNumbers); // logs [23, 65, 5]
// Same thing, but inline:
oddNumbers = [23, 65, 98, 5].myFilter((n) => n % 2 === 1);
console.log(oddNumbers); // logs [23, 65, 5]
// -----------------------------------------------------
// Again, comparing two identical ways of defining this.
let evenNumbers;
// Passing in a externally-defined function:
function isEven (n) {
return n % 2 === 0;
}
evenNumbers = [23, 65, 98, 5].myFilter(isEven);
console.log(evenNumbers); // logs [98]
// Same thing, but inline:
evenNumbers = [23, 65, 98, 5].myFilter((n) => n % 2 === 0);
console.log(evenNumbers); // logs [98]