Map and Filter and a freeCodeCamp Challenge

Hello fellow developers! Today I took a break from Node.js and went through some freeCodeCamp challenges. Particularly this challenge caught my attention because I will be using map() and filter() methods in Node.js quite often.

Firstly, I will go over both methods. After going over those methods I will solve the challenge. It's a nice refresher for me!

Map Method

The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.

The map() method creates a new array. So, the original array is not changed. It goes through every element of the array and returns the result of the function that is made inside of it. For example:

const numbers = [10, 20, 30, 40]

// Pass a function to map
const biggerNumbers = numbers.map(item => item + 10)

console.log(biggerNumbers) // output: [20, 30, 40, 50]
console.log(numbers) // [10, 20, 30, 40]

In the code above, JavaScript went through each element of the numbers array and added 10 to them. Now, can't we do it with a for loop? Yes, we can. A comparison between for loop and map method for this scenario.

For Loop VS. Map Method

const array1 = [10, 20, 30, 40];

// pass a function to map
const map1 = array1.map(x => x + 10);

console.log("With the map method: " + map1); // output: "With the map method: 20,30,40,50"

for (let i = 0; i < array1.length; i++) {
     array1[i] += 10
}
console.log("With for loop: " + array1) // output: "With for loop: 20,30,40,50"

The same result right? Nope :) Because when we did it with the for loop, we modified (changed) the original array. On the other hand, when we did it with the map() method, the original array is not touched, stayed the same.

When Not to Use the map() Method

It's tempting to think that using the map method instead of a for loop always makes sense, but it doesn't. If you will not use the returned new array from the map method, do not use the map method. It wastes memory. The worse, if you're not returning a value from the callback, do not use the map method. Use forEach() instead. Enough about the map, time to talk about the filter() method.

Filter Method

Imagine the filter method as a job opening, and there're candidates who apply for this vacancy. Candidates who pass the requirements will be interviewed. That is what the filter does. It filters the candidates, and its function is requirements. An example:

const candidates = [
    {
        fullname: "John Doe",
        jobTitle: "React Developer",
        experienceYears: 1
    },
    {
        fullname: "Micheal Shake",
        jobTitle: "React Developer",
        experienceYears: 3
    },
    {
        fullname: "name surname",
        jobTitle: "React Developer",
        experienceYears: 5
    }
]

const candidatePassed = candidates.filter(candidate => candidate.experienceYears > 3);

console.log(candidatePassed);
/*output { fullname: "name surname", jobTitle: "React Developer", experienceYears: 5 }*/

In the code above, we used the filter method to loop through the array. The function inside filter took candidate as its parameter. So, when a candidate's experience is greater than 3, that candidate was taken to interview (candidatePassed) array. Time to solve freeCodeCamp challenge.

Use the filter Method to Extract Data from an Array

  • Click here to go to the challenge
const watchList = [
  {
    "Title": "Inception",
    "Year": "2010",
    "Rated": "PG-13",
    "Released": "16 Jul 2010",
    "Runtime": "148 min",
    "Genre": "Action, Adventure, Crime",
    "Director": "Christopher Nolan",
    "Writer": "Christopher Nolan",
    "Actors": "Leonardo DiCaprio, Joseph Gordon-Levitt, Elliot Page, Tom Hardy",
    "Plot": "A thief, who steals corporate secrets through the use of dream-sharing technology, is given the inverse task of planting an idea into the mind of a CEO.",
    "Language": "English, Japanese, French",
    "Country": "USA, UK",
    "Awards": "Won 4 Oscars. Another 143 wins & 198 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg",
    "Metascore": "74",
    "imdbRating": "8.8",
    "imdbVotes": "1,446,708",
    "imdbID": "tt1375666",
    "Type": "movie",
    "Response": "True"
  },
  {
    "Title": "Interstellar",
    "Year": "2014",
    "Rated": "PG-13",
    "Released": "07 Nov 2014",
    "Runtime": "169 min",
    "Genre": "Adventure, Drama, Sci-Fi",
    "Director": "Christopher Nolan",
    "Writer": "Jonathan Nolan, Christopher Nolan",
    "Actors": "Ellen Burstyn, Matthew McConaughey, Mackenzie Foy, John Lithgow",
    "Plot": "A team of explorers travels through a wormhole in space in an attempt to ensure humanity's survival.",
    "Language": "English",
    "Country": "USA, UK",
    "Awards": "Won 1 Oscar. Another 39 wins & 132 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE@._V1_SX300.jpg",
    "Metascore": "74",
    "imdbRating": "8.6",
    "imdbVotes": "910,366",
    "imdbID": "tt0816692",
    "Type": "movie",
    "Response": "True"
  },
  {
    "Title": "The Dark Knight",
    "Year": "2008",
    "Rated": "PG-13",
    "Released": "18 Jul 2008",
    "Runtime": "152 min",
    "Genre": "Action, Adventure, Crime",
    "Director": "Christopher Nolan",
    "Writer": "Jonathan Nolan (screenplay), Christopher Nolan (screenplay), Christopher Nolan (story), David S. Goyer (story), Bob Kane (characters)",
    "Actors": "Christian Bale, Heath Ledger, Aaron Eckhart, Michael Caine",
    "Plot": "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.",
    "Language": "English, Mandarin",
    "Country": "USA, UK",
    "Awards": "Won 2 Oscars. Another 146 wins & 142 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_SX300.jpg",
    "Metascore": "82",
    "imdbRating": "9.0",
    "imdbVotes": "1,652,832",
    "imdbID": "tt0468569",
    "Type": "movie",
    "Response": "True"
  },
  {
    "Title": "Batman Begins",
    "Year": "2005",
    "Rated": "PG-13",
    "Released": "15 Jun 2005",
    "Runtime": "140 min",
    "Genre": "Action, Adventure",
    "Director": "Christopher Nolan",
    "Writer": "Bob Kane (characters), David S. Goyer (story), Christopher Nolan (screenplay), David S. Goyer (screenplay)",
    "Actors": "Christian Bale, Michael Caine, Liam Neeson, Katie Holmes",
    "Plot": "After training with his mentor, Batman begins his fight to free crime-ridden Gotham City from the corruption that Scarecrow and the League of Shadows have cast upon it.",
    "Language": "English, Urdu, Mandarin",
    "Country": "USA, UK",
    "Awards": "Nominated for 1 Oscar. Another 15 wins & 66 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BNTM3OTc0MzM2OV5BMl5BanBnXkFtZTYwNzUwMTI3._V1_SX300.jpg",
    "Metascore": "70",
    "imdbRating": "8.3",
    "imdbVotes": "972,584",
    "imdbID": "tt0372784",
    "Type": "movie",
    "Response": "True"
  },
  {
    "Title": "Avatar",
    "Year": "2009",
    "Rated": "PG-13",
    "Released": "18 Dec 2009",
    "Runtime": "162 min",
    "Genre": "Action, Adventure, Fantasy",
    "Director": "James Cameron",
    "Writer": "James Cameron",
    "Actors": "Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang",
    "Plot": "A paraplegic marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home.",
    "Language": "English, Spanish",
    "Country": "USA, UK",
    "Awards": "Won 3 Oscars. Another 80 wins & 121 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMTYwOTEwNjAzMl5BMl5BanBnXkFtZTcwODc5MTUwMw@@._V1_SX300.jpg",
    "Metascore": "83",
    "imdbRating": "7.9",
    "imdbVotes": "876,575",
    "imdbID": "tt0499549",
    "Type": "movie",
    "Response": "True"
  }
];

We have a watchlist variable. Our task is to make an array that shows only title and rating of the movies that have more than 8.0 imbdRating

In the watchlist array, the title is "Title", and rating happens to be "imdbRating". Note that "imdbRating" fields' values are string. My solution:

const filteredList = watchList.map(item => {
  let dataMap = {}

  dataMap.title = item.Title
  dataMap.imdbRating = item.imdbRating

  return dataMap
})

First, I mapped over the watchlist array. I created an object and called it dataMap. You can add new fields and values to objects by doing this:

var object = {}

object.name = "new name"
object.age = 24
object.bool = true
object.array = ["string", 12, false]

console.log(object) // output: { name: 'new name', age: 24, bool: true, array: [ 'string', 12, false ] }

Likewise, you can add field names as well. Like this

const filteredList = watchList.map(item => {
  let dataMap = {}

  dataMap.title = item.Title /* -> we tell JavaScript get item.Title(wacthList.Title) value and assign it to dataMap.title value
  */
  dataMap.imdbRating = item.imdbRating

  return dataMap /* output: [ { title: 'Inception', rating: '8.8' },
  { title: 'Interstellar', rating: '8.6' },
  { title: 'The Dark Knight', rating: '9.0' },
  { title: 'Batman Begins', rating: '8.3' },
  { title: 'Avatar', rating: '7.9' } ] */
})

Time to filter, add this code: .filter(item => parseFloat(item.rating) >= 8.0) Yes, there's a dot in the beginning. In short, we filtered elements looking through their rating value those are greater than or equal to 8.0. I used the parseFloat() method to turn strings (imdbRating fields' values are strings) to convert strings into decimal numbers, so we can compare two values.

That's all for now. Take care and keep coding