 # Map, Filter, Reduce - Code Exercises

Written by David Abram

It's really hard to test your programming knowledge after you have completed a tutorial or a lecture. We have prepared some exercises to help out beginner devs to solidify their understanding of Map, Filter, Reduce, and other useful array methods. Every exercise has a brief description of the problem, starting code, links to relevant MDN docs, and expected results. Try to solve the problems without taking a peek at the solution.

If you need some additional help, you can check out our Arrays video from #lockdown learning series in which we discuss Map, Filter and Reduce or contact the author of the article directly.

As a JavaScript developer, you will come across arrays. Arrays of numbers, arrays of objects, arrays of arrays of objects, multi-dimensional arrays, and you will need to simplify, transform or manipulate them.

You could use 'nested for loops' to solve most of the problems you will encounter, but that leaves the code hard to read and understand.

I would like to prove to you that by using Map, Filter, and Reduce array methods, not only will the code be more readable, but you will also be able to analyze the problem better and write the code with ease.

## Array squared

Square the value of every element in the array. Presume that you will only get numbers in the input array.

Input
``````const input = [1, 2, 3, 4, 5];
``````
Result
``````[1, 4, 9, 16, 25];
``````
Solution(click to show)
``````const input = [1, 2, 3, 4, 5];

input.map(function (num) {
return Math.pow(num, 2);
});

// or written with Arrow function
input.map((num) => Math.pow(num, 2));
``````

This code defines an array called input which contains the numbers 1 through 5. It then uses the `map()` method to iterate through each element of the array, which are numbers.

For each number, it applies the function passed to it, which is `Math.pow(num, 2)`, raising the number to the power of 2. Then it returns the new array with the squared value of each element of the input array.

The second version is the same as the first version but it uses `Arrow function` instead of anonymous function.

## Sum of every positive element

If the given input is an array of numbers, return the sum of all the positives ones. If the array is empty or there aren't any positive numbers, return 0.

Input
``````const input = [1, -4, 12, 0, -3, 29, -150];
``````
Result
``````42;
``````
Solution(click to show)
``````const input = [1, -4, 12, 0, -3, 29, -150];

input
.filter(function (num) {
return num > 0;
})
.reduce(function (accumulator, currentValue) {
return accumulator + currentValue;
}, 0);

// or written with Arrow function
input
.filter((num) => num > 0)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
``````

This code is using two higher-order functions, `filter` and `reduce`, to filter an array of numbers and then sum the remaining numbers.

The code first filters the input array to only include numbers greater than 0 using `filter` method and the callback function checks if the number is greater than 0. Then, it uses the reduce method to iterate through the filtered array and add each number to the `accumulator` (starting at 0), returning the sum of all the numbers greater than 0 in the input array.

The code is also written with `Arrow function` which are shorthand for writing function expressions that behave similarly to regular functions while being more concise.

## Calculate median and mean

Calculate the mean and median values of the number elements from the input array.

Input
``````const input = [12, 46, 32, 64];
``````
Result
``````  { mean: 38.5, median: 39 }
``````
Solution(click to show)
``````const input = [12, 46, 32, 64];
input.sort((a, b) => a - b);

input.reduce(
(accumulator, currentValue, index, array) => {
accumulator.mean += currentValue / array.length;

if (array.length % 2 === 0) {
// if the array has an even number of elements
if (index === array.length / 2 - 1) {
accumulator.median += currentValue;
} else if (index === array.length / 2) {
accumulator.median += currentValue;
accumulator.median /= 2;
}
} else {
// if the array has an odd number of elements
if (index === (array.length - 1) / 2) {
accumulator.median = currentValue;
}
}

return accumulator;
},
{ mean: 0, median: 0 }
);
``````

This code is working with an array of numbers and it is performing two operations on the array: sorting it, and then calculating its mean and median.

First, the `sort` method is used to sort the input array in ascending order. The function passed to the sort method compares two elements of the array, 'a' and 'b', and returns a negative number if 'a' should come before 'b', a positive number if 'b' should come before 'a', and 0 if they are equal. In this case, the function simply subtracts 'b' from 'a', so that the array is sorted in ascending order. The `reduce` method is then used to iterate through the sorted array and calculate the mean and median.

Furthermore, the function first adds the `currentValue` divided by the array length to the `mean` property of the accumulator object. Then, it uses an `if` statement to check if the current element is the median of the array. If so, it assigns the current element to the median property of the accumulator object.

Finally, the function returns the `accumulator` object with the updated mean and median values, after iterating through the entire array.

## Get name initials

The given input is a string of multiple words with a single space between each of them. Abbreviate the name and return the name initials.

Input
``````const input = "George Raymond Richard Martin";
``````
Result
``````"GRRM";
``````
Solution(click to show)
``````const input = "George Raymond Richard Martin";

input
.split(" ")
.map(function (word) {
return word;
})
.join("");

// or written with Arrow function
input
.split(" ")
.map((word) => word)
.join("");
``````

This code is working with a string of words and it is performing three operations on the string: splitting it, mapping the first letter of each word, and then joining them back together.

First, the `split` method is used to split the input string into an array of words using a space `(" ")` as the separator. Then, the `map` method is used to iterate through the array of words and create a new array by applying a function to each word. The function passed to the `map` method takes one argument, word, which is the current element being processed, and it returns the first letter of the word by using the bracket notation to access the first character of the string.

Finally, the `join` method is used to join all the elements of the new array of first letters back into a single string, with no separator.

The code is also written with `Arrow function` which are shorthand for writing function expressions that behave similarly to regular functions while being more concise.

## Age difference from the youngest and oldest

Find the difference in age between the oldest and youngest family members, and return their respective ages and the age difference.

Input
``````const input = [
{
name: "John",
age: 13,
},
{
name: "Mark",
age: 56,
},
{
name: "Rachel",
age: 45,
},
{
name: "Nate",
age: 67,
},
{
name: "Jennifer",
age: 65,
},
];
``````
Result
``````[13, 67, 54];
``````
Solution(click to show)
``````const input = [
{
name: "John",
age: 13,
},
{
name: "Mark",
age: 56,
},
{
name: "Rachel",
age: 45,
},
{
name: "Nate",
age: 67,
},
{
name: "Jennifer",
age: 65,
},
];

const ages = input.map((person) => person.age);

[Math.min(...ages), Math.max(...ages), Math.max(...ages) - Math.min(...ages)];
``````

This code is working with an array of objects, each representing a person with properties name and age. It performs three operations: mapping the age of each person, calculating the minimum, maximum, and range of the ages.

First, the `map` method is used to iterate through the array of objects, and create a new array by applying a function to each person object. The function passed to the `map` method takes one argument, person, which is the current element being processed, and it returns the value of the age property of the person object.

The `Math.min` method is then used with the spread operator `(...)` to find the minimum value of the ages array, followed by the `Math.max` method to find the maximum value.

Finally, the difference between the max and min is calculated and returned in an array.

## Numeronyms

Devs like to abbreviate everything: k8s means Kubernetes, a11y means accessibility, l10n means localization. You get the Dev numeronyms by taking the first and the last letter and counting the number of letters in between. Words that have less than 4 letters aren't abbreviated, because that would just be odd. The input is a sentence, and you should abbreviate every word that is 4 letters long or longer. There won't be any punctuation in the sentence. g2d l2k e6e

Input
``````const input = "Every developer likes to mix kubernetes and javascript";
``````
Result
``````"E3y d7r l3s to mix k8s and j8t";
``````
Solution(click to show)
``````const input = "Every developer likes to mix kubernetes and javascript";

const createNumeronym = (word) =>
word + (word.length - 2) + word[word.length - 1];

input
.split(" ")
.map(function (word) {
if (word.length >= 4) {
return createNumeronym(word);
}
return word;
})
.join(" ");

// or written with Arrow function and Conditional operator
input
.split(" ")
.map((word) => (word.length >= 4 ? createNumeronym(word) : word))
.join(" ");
``````

This code defines a function called `createNumeronym` that takes in a word as an argument, and returns a new word consisting of the first letter, the length of the word minus 2, and the last letter of the original word. It then takes a string input, which is "Every developer likes to mix kubernetes and javascript", split it into an array of words using `.split(" ")`.

In order to iterate through each word in the array it uses `.map()`, and for each word that has a length of 4 or more characters, it calls the `createNumeronym` function on that word, and replaces it with the returned value. For words that are shorter than 4 characters, it keeps the original word.

Finally, it uses the `join()` method to join the array of modified words back into a single string.

The second version is the same as the first version but it uses `Arrow function` and `Conditional operator`.

## n! with Map and Reduce

If the given input is a number, you should return the factorial of that number. The factorial of a natural number n is the product of the positive integers less than or equal to n. So, 2! = 2, 3! = 6, 4! = 24 and so on.

Input
``````const input = 6;
``````
Result
``````720;
``````
Solution(click to show)
``````const input = 6;

const array = new Array(input).fill(null);
// array is [null, null, null, null, null, null]

array
.map(function (currentValue, index) {
return index + 1;
})
.reduce(function (accumulator, currentValue) {
return accumulator * currentValue;
});

// or written with Arrow function
new Array(input)
.fill(null)
.map((currentValue, index) => index + 1)
.reduce((accumulator, currentValue) => accumulator * currentValue);
``````

This code is working with a number input, it creates an array of that length filled with null values and then performs two operations on that array: mapping each element to its `index` + 1, and then reducing the array to the product of all its elements.

First, new `Array(input).fill(null)` creates a new array with the length of input and fills it with null values. Then, the `map` method is used to iterate through the array and create a new array by applying a function to each element. The function passed to the `map` method takes two arguments, `currentValue` and `index`, and it returns the value of the `index` plus 1, effectively mapping each element to its `index` + 1.

Finally, the `reduce` method is used to iterate through the new array and calculate the product of all its elements. The function passed to the `reduce` method takes two arguments, `accumulator` and `currentValue`, and it multiplies the `currentValue` to the `accumulator` and returns the new value of the `accumulator`.

The code is also written with `Arrow function` which are shorthand for writing function expressions that behave similarly to regular functions while being more concise.

## Count elements in array of arrays

Count the occurrences of distinct elements in the given 2D array. The given input is an array, the elements of which are arrays of strings. The result is an object whose property names are the values from the arrays and their value is the number of their occurrences.

Input
``````const input = [
["a", "b", "c"],
["c", "d", "f"],
["d", "f", "g"],
];
``````
Result
``````  {
a: 1,
b: 1,
c: 2,
d: 2,
f: 2,
g: 1,
}
``````
Solution(click to show)
``````const input = [
["a", "b", "c"],
["c", "d", "f"],
["d", "f", "g"],
];

input.flat().reduce((accumulator, currentValue) => {
if (accumulator[currentValue]) {
accumulator[currentValue] += 1;
} else {
accumulator[currentValue] = 1;
}
return accumulator;
}, {});
``````

This code is working with an array of arrays, flattening it and then counting the occurrences of each character in the flattened array.

First, the `flat` method is used to flatten the array of arrays into a single array of characters. Then, the `reduce` method is used to iterate through the flattened array and count the occurrences of each character. The function passed to the `reduce` method takes two arguments, `accumulator` and `currentValue`.

The function checks if the `currentValue` already exists in the `accumulator` object, if it does, it increments the value by 1 and if not, it assigns the value 1 to that key, effectively counting the occurrences of each character in the flattened array.

Finally, the function returns the `accumulator` object with the count of each character in the flattened array.

## High performing students

You are given an array of objects representing a group of students, each with a name and an array of test scores. Your task is to use map, filter, and reduce to calculate the average test score for each student, and then return an array of objects containing only the students who have an average score above 90.

Input
``````const students = [
{ name: "Alice", scores: [90, 85, 92] },
{ name: "Bob", scores: [75, 80, 85] },
{ name: "Charlie", scores: [90, 95, 85] },
{ name: "David", scores: [100, 100, 100] }
];
``````
Result
``````[
{ name: 'Jack', average: 100 }
]
``````
Solution(click to show)
``````const students = [
{ name: "Alice", scores: [90, 85, 92] },
{ name: "Bob", scores: [75, 80, 85] },
{ name: "Charlie", scores: [90, 95, 85] },
{ name: "Jack", scores: [100, 100, 100] }
];

// Use map to calculate the average test score for each student
const studentAverages = students.map(student => {
const sum = student.scores.reduce((acc, score) => acc + score);
return { name: student.name, average: sum / student.scores.length };
});

// Use filter to only select students with an average above 90
const highPerformers = studentAverages.filter(student => student.average > 90);
``````

This code is working with an array of objects representing students and their test scores, it performs two operations: calculating the average test score for each student and then filtering the students with an average test score above 90.

First, the `map` method is used to iterate through the array of students, and create a new array by applying a function to each `student` object. The function passed to the `map` method takes one argument, `student`, which is the current element being processed.

It calculates the sum of all the test scores using the `reduce` method on the scores array and then returns an object with the student's name and average test score which is the sum of scores divided by the number of scores. Then, the `filter` method is used to iterate through the array of student averages, and create a new array by applying a function to each `student` object.

The function passed to the `filter` method takes one argument, `student`, which is the current element being processed, and it returns a Boolean value that indicates whether the student's average test score is greater than 90 or not.

## High Priced Product Categories

You are given an array of objects representing a collection of products, each with a name, price, and category. Your task is to use map, filter, and reduce to calculate the average price of products in each category, and then return an array of objects containing only the categories that have an average price above 50.

Input
``````const products = [
{ name: "Product 1", price: 20, category: "Electronics" },
{ name: "Product 2", price: 30, category: "Clothes" },
{ name: "Product 3", price: 40, category: "Electronics" },
{ name: "Product 4", price: 50, category: "Clothes" },
{ name: "Product 5", price: 60, category: "Clothes" },
{ name: "Product 6", price: 70, category: "Electronics" },
{ name: "Product 7", price: 80, category: "Clothes" },
{ name: "Product 8", price: 90, category: "Electronics" },
];
``````
Result
``````[
{ category: 'Clothes', average: 55 },
{ category: 'Electronics', average: 55 }
]
``````
Solution(click to show)
``````const products = [
{ name: "Product 1", price: 20, category: "Electronics" },
{ name: "Product 2", price: 30, category: "Clothes" },
{ name: "Product 3", price: 40, category: "Electronics" },
{ name: "Product 4", price: 50, category: "Clothes" },
{ name: "Product 5", price: 60, category: "Clothes" },
{ name: "Product 6", price: 70, category: "Electronics" },
{ name: "Product 7", price: 80, category: "Clothes" },
{ name: "Product 8", price: 90, category: "Electronics" },
];

/* Use map to create a dictionary with category as the key
and an array of products as the value */
const productsByCategory = products.reduce((acc, product) => {
const category = product.category;
if (!acc[category]) {
acc[category] = [];
}
acc[category].push(product);
return acc;
}, {});

// Use map to calculate the average price for each category
const avgPriceByCategory = Object.keys(productsByCategory).map(category => {
const sum = productsByCategory[category].reduce((acc, product) => acc + product.price, 0);
return { category: category, average: sum / productsByCategory[category].length };
});

// Use filter to only select categories with an average above a certain threshold
const highPricedCategories = avgPriceByCategory.filter(category => category.average > 50);
``````

This code is using JavaScript's `reduce` and `map` methods to process an array of products and group them by category, calculate the average price of each category, and then `filter` the categories that have an average price greater than 50.

It starts by using the `reduce` method on the array of products and an empty object as an initial `accumulator`. The `callback` function passed to `reduce` takes in two arguments: an `accumulator` object and the current `product`.

It assigns the product's category to a variable category, and checks if the `accumulator` object already contains a key for this category. If it doesn't, it creates a new key on the `accumulator` object with an empty array as its value. It then pushes the current `product` into the array of the corresponding category and returns the `accumulator` object.

In the end, `productsByCategory` will be an object where each key is a category name, and the value is an array of products that belong to that category.

Next, it uses `Object.keys(productsByCategory)` to extract the keys (category names) of the `productsByCategory` object and then `map` method to iterate over these keys and calculate the average price of products in each category. It calculates the sum of prices of all products in each category using `reduce` method and divides this sum with the number of products in that category.

Finally, it filters the categories that have an average price greater than 50 using `filter` method.

## HR VS IT Department

You are given an array of objects representing a collection of employees, each with a name, salary, and department. Your task is to use map, filter, and reduce to calculate the average salary for each department and then return an array of objects containing only the departments that have an average salary above 65000.

Input
``````const employees = [
{ name: "John", salary: 50000, department: "IT" },
{ name: "Jane", salary: 60000, department: "HR" },
{ name: "Bob", salary: 55000, department: "IT" },
{ name: "Sophie", salary: 75000, department: "HR" },
{ name: "Mike", salary: 65000, department: "IT" },
{ name: "Emily", salary: 80000, department: "HR" },
{ name: "David", salary: 70000, department: "IT" },
];
``````
Result
``````[
{ department: 'HR', average: 71666 }
]
``````
Solution(click to show)
``````const employees = [
{ name: "John", salary: 50000, department: "IT" },
{ name: "Jane", salary: 60000, department: "HR" },
{ name: "Bob", salary: 55000, department: "IT" },
{ name: "Sophie", salary: 75000, department: "HR" },
{ name: "Mike", salary: 65000, department: "IT" },
{ name: "Emily", salary: 80000, department: "HR" },
{ name: "David", salary: 70000, department: "IT" },
];

/* Use reduce to create a dictionary with department as the key
and an array of employee objects as the value */
const employeesByDepartment = employees.reduce((acc, employee) => {
const department = employee.department;
if (!acc[department]) {
acc[department] = [];
}
acc[department].push(employee);
return acc;
}, {});

// Use map to calculate the average salary for each department
const avgSalaryByDepartment = Object.keys(employeesByDepartment).map(department => {
const sum = employeesByDepartment[department].reduce((acc, employee) => acc + employee.salary, 0);
return { department: department, average: sum / employeesByDepartment[department].length };
});

// Use filter to only select departments with an average above a certain threshold
const highPaidDepartments = avgSalaryByDepartment.filter(department => department.average > 65000);
``````

This code is working with an array of objects representing employees and their salaries and department. It performs three operations: creating a dictionary with `department` as the key and an array of `employee` objects as the value, calculating the average salary for each department, and filtering the departments with an average salary above a certain threshold.

First, the `reduce` method is used to iterate through the array of employees, and create a dictionary object by applying a function to each `employee` object. The function passed to the `reduce` method takes two arguments, `acc` and `employee`, where `acc` is the `accumulator` object, initially set to an empty object, and `employee` is the current element being processed.

The function first gets the department from the current `employee` object, and if the department does not exist in the `accumulator` object, it creates an array for that department. Then it pushes the current `employee` object to the array for that department. Finally, it returns the `accumulator` object with the updated `department` and `employee` arrays.

The `Object.keys` method is then used to get all the departments from the `accumulator` object, then the `map` method is used to iterate through the departments and create a new array by applying a function to each `department`. The function passed to the `map` method takes one argument, `department`, which is the current element being processed.

It first calculates the sum of all the salary of employees in that department using the `reduce` method on the `department` array and then returns an object with the department name and average salary which is the sum of salary divided by the number of employees in that `department`.

Finally, the `filter` method is used to iterate through the array of department averages, and create a new array by applying a function to each `department` object. The function passed to the `filter` method takes one argument, `department`, which is the current element being processed, and it returns a Boolean value that indicates whether the department's average salary is greater than 65000 or not.