What's the difference between .filter() and .map()?

Question

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

Extra Study

Given the expression patterns,

Array.filter(callback)
Array.map(callback)

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).

10 Likes

Hello.
Trying to solve challenge №10 I got absolutely confused how JS works…

  1. 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?

Thanks in advance who open my eyes…

1 Like

The above is known as a predicate function since it returns a boolean, either true or false.

firstArray.filter(predicate_function)

The filter method will iterate through firstArray and return an array of only values that pass the predicate function.

3 Likes

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

1 Like

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)
}

const coolStuff = [‘gameboys’, ‘skateboards’, ‘backwards hats’, ‘fruit-by-the-foot’, ‘pogs’, ‘my room’, ‘temporary tattoos’];

const myStuff = [ ‘rules’, ‘fruit-by-the-foot’, ‘wedgies’, ‘sweaters’, ‘skateboards’, ‘family-night’, ‘my room’, ‘braces’, ‘the information superhighway’];

console.log(justCoolStuff(myStuff, coolStuff))`

Also in the first solution I do not understand what item is…

function justCoolStuff(firstArray, secondArray) {
  function isInSecondArray(item){
    for(let x of secondArray){
      if (x === item){
        return true
      }
    }
    return false
  }
  return firstArray.filter(isInSecondArray)
}

What is happening in the filter method?

1 Like

The filter comes up with item by comparing the two arrays?

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.

1 Like

My result with loop for :grinning:

// Write your code here: const justCoolStuff = (arr1, arr2) => { const arr3 = []; for(let i = 0; i < arr1.length; i++){ for (let j = 0; j < arr2.length; j++){ if ( arr1[i] === arr2[j]){ arr3.push(arr1[i]); } } } return arr3; } // Feel free to uncomment the code below to test your function const coolStuff = ['gameboys', 'skateboards', 'backwards hats', 'fruit-by-the-foot', 'pogs', 'my room', 'temporary tattoos']; const myStuff = [ 'rules', 'fruit-by-the-foot', 'wedgies', 'sweaters', 'skateboards', 'family-night', 'my room', 'braces', 'the information superhighway']; console.log(justCoolStuff(myStuff, coolStuff)) // Should print [ 'fruit-by-the-foot', 'skateboards', 'my room' ]

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

Hi all,

This is how I wrote it in my first attempt and would you believe? it worked :smiley: . The hint suggests a different method, so I’m curious to explore that too now.

const justCoolStuff = (arr1, arr2) => {

const both =

arr1.filter(words1 => {

arr2.filter(words2 => { 

if(words1 === words2) {

  return both.push(words1)
}})

})
return both;
}

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.

1 Like

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.

const justCoolStuff = (arr1,arr2) => {
const newArr = ;
for (let i=0; i < arr1.length; i++) {
for (let j=0; j < arr2.length; j++) {
if(arr1[i]) === arr2[j]{
newArr.push(arr1[i]);
}}}
return newArr;
}

The above is perfectly fine as an imperative approach. The first refinement would be to switch from indices to values…

for (let x of arr1) {
  for (let y of arr2) {
    if (x == y) {
      newArr.push(x)
    }
  }
}

The alternative is called declarative, and reads like an expression.

return arr1.filter(x => arr2.includes(x))

Eg.

a = [1,3,5,7,9]
b = [2,3,4,5,6,7]
console.log(a.filter(x => b.includes(x)))
[ 3, 5, 7 ]

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?

Thanks so much in advance for your time :blush:

AHA! @mtf After a little playing around, I see now that the fully refined version with the declarative would look like so:

let justCoolStuff = (arr1, arr2) => {
   return arr1.filter(x => arr2.includes(x))
}

:exploding_head: Didn’t know things could be so simple! According to this article, the author describes the difference between imperative vs. declarative paradigms:

Imperative means you tell the compiler what you exactly want to happen, while in declarative paradigm you only specify what you want the result to be.

Can you expand on this at all?

Cheers! :hugs:

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.