What’s the difference between .filter() and .map()?
Answer
While both the .filter() and .map() methods will return a new array, .filter() will create a new array of array elements that pass a given test while .map() will create a new array made up of the results of calling a function on each array element.
.filter() example:
var arrOfNums = [2, 18, 42, 31, 17, 90, 5];
function isNumGreaterThanTwenty (num) {
return num > 20; //returns a boolean, true when num is greater than 20, false when num is less than or equal to 20
}
var arrOfNumsGreaterThanTwenty = arrOfNums.filter(isNumGreaterThanTwenty); //the arrOfNumsGreaterThanTwenty variable is assigned a newly created array filled with the elements from arrOfNums that pass the test provided by isNumGreaterThanTwenty
console.log(arrOfNumsGreaterThanTwenty); //[42, 31, 90], our new array, is logged to the console
.map() example:
var arrOfNums = [2, 18, 42, 31, 17, 90, 5];
function addFive (num) {
return num + 5; //returns whatever num is plus 5
}
var arrOfNumsPlusFive = arrOfNums.map(addFive); //assigns the arrOfNumsPlusFive variable to a new array of elements created by looping over arrOfNums and applying the addFive function on each element
console.log(arrOfNumsPlusFive); //[ 7, 23, 47, 36, 22, 95, 10 ] is logged to the console
note that the callback is not invoked, as in, callback()? Why is it written this way? We hand the function to the iterator by reference, only. The iterator has an internal variable that it will pass to the function on each element in the array.
We can emulate this by passing the whole function…
Array.filter(x => x > 20)
Array.map(x => x + 5)
Notice how the function is called on each element? By this time one will be well informed about arrow function syntax, so consider that we take full advantage of its short form. It’s actually useful to write code this way if the callback function can be reduced to this minimum (single line, implicit return, no braces or parens on formal parameter) since it doesn’t pollute the namespace with functions and takes less space in memory.
More complex code is preferably abstracted away to a local function, or if the same callback is used by multiple iterators or events. Then it is useful as it prevents repetition.
const greaterThanTwenty = x => x > 20;
const addFive = x => x + 5;
Botom line, simple one-offs do not need a dedicated callback function. Write it directly into the argument of the iterator (or event listener).
Hello.
Trying to solve challenge №10 I got absolutely confused how JS works…
Can somebody explain me how this code works?
“const justCoolStuff = (firstArray, secondArray) =>
firstArray.filter(item =>
secondArray.includes(item))”
This is what I got when got solution, because I did’t absolutely imagine how to solve this task…
2) Why to use such invenion in embedded methods like this filter()? Instead of this would be possible to use two wrapped one in another loops (for loop) which compares each element of two arrays?
Ok, thanks…It has become more clear for me when I wrote this code using two function (one inside another) and for loop.
It’s gonna be a little difficult to get used to JS6 syntax
Thanks a lot for help
Hey could I get some clarity on the declaration w/ loop solution? I understand the first solution with the item parameter and the .includes() method comparing the items of the arrays and returning a boolean. I don’t understand how the item parameter works in the declaration w/loop. How does the if statement come up with a value for item?
`// As a function declaration AND using named function w/ a loop:
function justCoolStuff(firstArray, secondArray) {
function isInSecondArray(item){
for(let i = 0; i < secondArray.length; i++){
if (secondArray[i] === item){
return true
}
}
return false
}
return firstArray.filter(isInSecondArray)
}
function justCoolStuff(firstArray, secondArray) {
function isInSecondArray(item){
for(let x of secondArray){
if (x === item){
return true
}
}
return false
}
return firstArray.filter(isInSecondArray)
}
Close, item is the iteration variable for the filter method. It is the current item from firstArray as filter iterates over it and passes it to the callback function.
Note in our example above using a revision of your code we only iterate the items in the second array, and do not need to poll their index. I often refer to this as a read-only loop since that is all it can do, read; and, all we need are the values, not their index.
LOL that’s how I first tried to solve it. But of course it failed me since the problem required using the .filter() method, so here I am after diving into .filter() documentation trying to understand how to use it to compare two arrays. It’s still good to know we are learning many ways to accomplish the same task. The single-line .filter() solution that @mtf provided was so much more elegant than our big ugly nested for loops though LOL
This is how I wrote it in my first attempt and would you believe? it worked . The hint suggests a different method, so I’m curious to explore that too now.
The thing to note is that Array.filter() is an IF, only repeated over every element in Array. We do not need an if statement in a filter. Moreover, it returns an array so a .push() statement is rather out of place there.
You’ve got it down that we need to iterate both objects, but using the filter iterator on both is not quite the approach. Does the suggested solution include both .filter() and .includes()? That’s the path I would suggest.
Yes, I just played with the .includes() and is miles better, thanks for your feedback.
I was happy I got a green tick with my first try, but less happy now seeing there were better methods out there I didn’t think of, just have to keep at it.
Can I also ask you how does the below compare to my not so appropriate solution above? it does look similar and is it also not a good approach? Thanks.
Hey @mtf I suppose the full solution including your refinement to @digital0084557329 's code would look like so:
const justCoolStuff = (arr1, arr2) => {
const newArr = [];
for (let x of arr1) {
for (let y of arr2) {
if (x == y) {
newArr.push(x)
}
}
}
return newArr
}
I put the above into the code editor for challenge 10 and got the expected result.
My question is regarding the declarative you mentioned. You say it is an alternative… alternative to what part, exactly? What is its purpose?
When I replace return newArr with return arr1.filter(x => arr2.includes(x)) in the above code, I still get the expected result. But why/when would we use such a statement if return newArr is simpler?
You see how the imperative model uses instruction code to carry out an algorithm step by step. We are comparing two arrays using nested loops, an if statement and Array.push() then returning the final array. That’s all we can return from that, after all the loops are completed. The construct itself is made up of statements which cannot be returned or used in place of an expression.
const justCoolStuff = (a, b) => a.filter(x => b.includes(x))
Right down to its simplest form, the concise body arrow function with no braces and implicit return. The assignment is a statement but the function is an expression that contains an expression which can be returned. That’s declarative.
We don’t see the steps of the algorithm, only the complete expression. There are still two loops, filter iterates over array a and includes iterates over array b but there internal workings are likely faster than the nested loops. The return is still an array of common values.
Bottom line, the main difference is the iterators are more functional and result oriented. It takes some practice with imperative algorithms to be able to properly weigh the value of declarative code. Expressions are at the heart of it.