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]