How to Count the Occurrences of Each Element in an Array in JavaScript
A very common data analysis task is to count the frequency of each unique element in an array. This is useful for creating histograms, summarizing data, or finding the most common value in a list. While you could do this with a manual loop, the most concise and idiomatic modern approach is to use the Array.prototype.reduce() method.
This guide will teach you how to use reduce() to efficiently count element occurrences and build a frequency map. We will also cover the classic for...of loop to illustrate the underlying logic.
The Core Task: Creating a Frequency Map
The goal is to transform an array of values into an object (or a Map) where the keys are the unique elements from the array and the values are the number of times each element appeared. This is often called a "frequency map" or "histogram."
Problem, you have an array with duplicate values and need to count each one.
// Problem: How to count the 'a's, 'b's, and 'c's in this array?
const letters = ['a', 'b', 'a', 'c', 'b', 'a'];
Desired Output: { a: 3, b: 2, c: 1 }
The Functional Method (Recommended): Array.prototype.reduce()
The reduce() method is the perfect tool for this because it is designed to "reduce" an array down to a single value—in this case, our final counts object.
This concise, functional approach is the best practice.
const letters = ['a', 'b', 'a', 'c', 'b', 'a'];
const counts = letters.reduce((accumulator, value) => {
// If the key for the value already exists, increment it.
// Otherwise, initialize it to 1.
accumulator[value] = (accumulator[value] || 0) + 1;
return accumulator;
}, {}); // `{}` is the initial value of our accumulator
console.log(counts); // Output: { a: 3, b: 2, c: 1 }
How the reduce() Method Works
reduce((accumulator, value) => { ... }, {}): We callreducewith a callback function and an initial value for our accumulator, which is an empty object{}.- First Iteration:
accumulatoris{},valueis'a'. The expressionaccumulator['a'] || 0evaluates to0, so we setaccumulator['a'] = 0 + 1. The accumulator is now{ a: 1 }. - Second Iteration:
accumulatoris{ a: 1 },valueis'b'.accumulator['b'] || 0is0, so we setaccumulator['b'] = 1. The accumulator is now{ a: 1, b: 1 }. - Third Iteration:
accumulatoris{ a: 1, b: 1 },valueis'a'.accumulator['a'] || 0is1, so we setaccumulator['a'] = 1 + 1. The accumulator is now{ a: 2, b: 1 }. - This process continues until the final object is returned.
The Manual Looping Method: Using a for...of Loop
The classic imperative approach is to create an empty object and manually populate it within a loop. This is more verbose but can be easier to understand for beginners.
const letters = ['a', 'b', 'a', 'c', 'b', 'a'];
const counts = {};
for (const element of letters) {
if (counts[element]) {
counts[element]++;
} else {
counts[element] = 1;
}
}
console.log(counts); // Output: { a: 3, b: 2, c: 1 }
While this works perfectly, the reduce() method is generally preferred in modern JavaScript for its conciseness and declarative style.
Bonus: Counting the Occurrences of a Single, Specific Element
If you don't need to count every element, but just one specific element, the problem becomes much simpler. The best tool for this is Array.prototype.filter().
The logic: Filter the array to get a new array containing only the element you're looking for, then get the length of that new array.
Solution:
const letters = ['a', 'b', 'a', 'c', 'b', 'a'];
const countOfA = letters.filter(element => element === 'a').length;
const countOfB = letters.filter(element => element === 'b').length;
console.log(`The letter 'a' appears ${countOfA} times.`); // Output: 3
console.log(`The letter 'b' appears ${countOfB} times.`); // Output: 2
Conclusion
For counting the occurrences of each element in an array, modern JavaScript offers clean, functional solutions.
- The
reduce()method is the recommended best practice for creating a complete frequency map. It is a concise and powerful functional approach. - A
for...ofloop is a perfectly valid but more verbose, imperative alternative. - If you only need to count a single specific element, use the much simpler
.filter().lengthpattern.
By choosing the right method for your specific goal, you can write code that is not only correct but also clean and easy to read.