Introduction
JavaScript's Array iterator methods .map and .reduce were some of the more confusing things to learn as a new JavaScript programmer. In this blog I walk through each method and explain how to use them. As a beginner myself, I hope to demonstrate my own learning and help other beginners who may also struggle to understand these methods.
I'll use an array of students where each student object has keys studentId, name, age, score, and classes (an array of Class IDs the student is enrolled in).
const students = [
{ id: "A001", name: "Alice", age: 22, gpa: 4.0, classes: ["C101", "C102", "C103"] },
{ id: "B002", name: "Bob", age: 24, gpa: 3.5, classes: ["C101", "C104"] },
{ id: "C003", name: "Charlie", age: 23, gpa: 3.6, classes: ["C102", "C105"] },
{ id: "D004", name: "David", age: 25, gpa: 2.9, classes: ["C103", "C106"] },
{ id: "E005", name: "Eve", age: 21, gpa: 3.0, classes: ["C104", "C105", "C106"] }
];
.map()
- Description: iterates over an array and applies a callback function to each element, modifying them in some way
- Arguments: a callback function
- Returns: a new array with the elements that have been modified by the callback function
Use .map to create a new array using an object key
.map makes it super quick to get a list of particular values from an array of objects using a key. For example, we can use .map to get a list of studentIds
const studentIds = students.map(student => student.id)
//[ 'A001', 'B002', 'C003', 'D004', 'E005' ]
This uses a function expression with an implicit return. This is basically saying, for each student, get their ID, and return the ID to the new studentIds array.
Use .map to create a new array of objects with additional data
We can also use map to get create a new list of students with their IDs and the count of classes they are enrolled in, based on the length of the nested classes array.
const studentClassCount = students.map(student => {
return {
id: student.id,
countOfClasses: student.classes.length
}
})
/*
LOG: [
{ id: 'A001', countOfClasses: 3 },
{ id: 'B002', countOfClasses: 2 },
{ id: 'C003', countOfClasses: 2 },
{ id: 'D004', countOfClasses: 2 },
{ id: 'E005', countOfClasses: 3 }
]
*/
Because this use of .map is constructing new objects, the anonymous function that's passed to .map has to explicitly return each object with the student id and the new countOfClasses key that gets the length of each student's nested classes array.
.reduce()
- Description: iterates over an array and applies a function to each element and calculates a single value
- Arguments: a callback function (which can have 3 arguments) and an initial value to start
- Returns: A single value (such as a string, integer, boolean, or another object/array)
Reduce is helpful for calculating a single value from an array, such as a string, integer, boolean, or another object/array. But its argument structure can be difficult to understand. Let's break it down:
- The first argument is a callback function, and this function itself can have three arguments:
An
accumulator(sometimes abbreviated asaccumoracc), which is the value that will be added to (or accumulated) with each iteration over the array, and it will be passed into the next iteration. This accumulator will be the thing that is returned byreduceonce the entire array has been iterated over with the callback function.A current value (sometimes written as
value), which will represent each array element as it is passed to the callback functionAn index, an optional argument that indicates which index in the array for the function to start at. If this is not provided, the callback function will start with index
0by default (the first element in the array).
- An initial value to start with, such as
0if you're calculating a numeric value, or an object/array. Objects can be empty, but you can include new keys if needed.
To demonstrate .reduce and these arguments, let's use a simple array of numbers and sum them together.
const numbers = [1, 2, 3];
const sum = numbers.reduce((acc, value, index) => {
console.log(`Index: ${index}, Accumulator: ${acc}, Value: ${value}`);
return acc + value;
}, 0);
/* LOG:
Index: 0, Accumulator: 0, Value: 1
Index: 1, Accumulator: 1, Value: 2
Index: 2, Accumulator: 3, Value: 3
*/
console.log(sum)
//LOG: 6
- We call reduce on the
numbersarray, and pass an arrow callback function that has 3 arguments:acc,value, `index - The callback function does 2 things for each iteration: it first console logs each of the arguments, and it returns the sum of
accandvalue - After the callback function, note that
0is provided as the second argument to.reduce. This is the initial value ofaccthat the sum will start with. - In the first iteration, the
indexstarts at0, theaccis0(the initial value provided as second argument to.reduce), and the currentvalueis the first element in the array:1 - The callback function returns
acc + value, or0 + 1which equals1. -
1is then passed into the second iteration as theacc. The index is now1, accumulator is1, and the next array value in the array is now2 - This repeats for each element in the array.
-
sumultimately returns6as the sum of1 + 2 + 3
Now let's return to our students example and see what we can do with .reduce.
Use reduce to calculate a single value
If we wanted to calculate an average GPA for our set of students, we can use .reduce to get the total GPA which can then be used to calculate an average.
`javascript
const totalGPA = students.reduce((accumulator, student) => {
return accumulator + student.gpa;
}, 0);
const averageGPA = totalGPA / students.length;
//LOG: Total GPA: 17
//LOG: Average GPA: 3.4
`
Use reduce to create a new object
We want to categorize our students based on their GPA scores. To do this, we'll want to loop through each student's GPA and determine where each GPA falls in our categories.
`javascript
const gpaCategories = students.reduce((accumulator, student) => {
let category;
if (student.gpa === 4.0) {
category = "4.0";
} else if (student.gpa >= 3.5) {
category = "3.5-3.9";
} else if (student.gpa >= 3.0) {
category = "3.0-3.4";
} else {
category = "below 3.0";
}
if (!accumulator[category]) {
accumulator[category] = [];
}
accumulator[category].push(student.name);
return accumulator;
}, {});
`
The callback function uses if/else statements to determine the category in which each GPA falls. The second if statement creates the category keys in the accumulator object after checking whether the category key already exists.
Then each student name is pushed into the category key according to their GPA.
This will return a new object:
javascript
{
'4.0': [ 'Alice' ],
'3.5-3.9': [ 'Bob', 'Charlie' ],
'below 3.0': [ 'David' ],
'3.0-3.4': [ 'Eve' ]
}
Conclusion
In this blog I demonstrated how .map and .reduce can be used, providing a break down of each method's arguments and inner workings. .map is a powerful and concise method for creating new arrays of modified elements, while .reduce can derive a single calculated value or object/array.
Happy learning!
Top comments (0)