Skip to main content

How to Find the Indexes of All Occurrences of an Element in a JavaScript Array

While JavaScript's indexOf() method is great for finding the first index of an element, a common and more advanced task is to find the indexes of all occurrences of that element. This is useful for data analysis, highlighting all instances of a search term, or replacing multiple items in a list.

This guide will teach you the most effective and readable methods for this task. We will cover the functional reduce() approach and the classic forEach loop, explaining the use case for each and why they are the standard solutions for this problem.

The Core Problem: Finding More Than Just the First Index

The indexOf() method stops as soon as it finds the first match, which is not what we need.

For example:

// Problem: How to find all indexes of 'a', which are 0, 2, and 4?
const letters = ['a', 'b', 'a', 'c', 'a'];

// indexOf() only gives us the first one.
console.log(letters.indexOf('a')); // Output: 0

To solve this, we must iterate through the entire array and collect the index of every matching element.

The reduce() method is a powerful and concise tool for this job. It is designed to "reduce" an array to a single value, which in our case will be the array of indexes we are building.

The logic:

  1. Use .reduce() to iterate over the array. The reduce callback provides access to the accumulator (the array of indexes we are building), the currentValue, and the currentIndex.
  2. Initialize the accumulator as an empty array ([]).
  3. On each iteration, check if the currentValue matches our target.
  4. If it does, push the currentIndex into the accumulator.
  5. Always return the accumulator for the next iteration.

This is the recommended functional approach.

const letters = ['a', 'b', 'a', 'c', 'a'];
const target = 'a';

const indexes = letters.reduce((accumulator, currentValue, currentIndex) => {
if (currentValue === target) {
accumulator.push(currentIndex);
}
return accumulator;
}, []);

console.log(indexes); // Output: [0, 2, 4]

The Manual Looping Method: forEach() or for...of

The classic imperative approach is to create an empty array and manually populate it within a loop. This is more verbose but can be easier to understand for beginners.

The forEach() method provides both the element and its index in its callback, making it a good choice for this.

const letters = ['a', 'b', 'a', 'c', 'a'];
const target = 'a';
const indexes = [];

letters.forEach((element, index) => {
if (element === target) {
indexes.push(index);
}
});

console.log(indexes); // Output: [0, 2, 4]
note

While this works perfectly, the reduce() method is often preferred in modern JavaScript for its conciseness and declarative, functional style.

A Clever (but Less Readable) Alternative: map() and filter()

You can also achieve this result by chaining map() and filter(). This method is clever but generally considered less readable and less direct than the reduce() or forEach() approaches.

The logic:

  1. Use map() to transform the array into a new array that contains either the index (if the element matches) or a placeholder value (like null or -1).
  2. Use filter() to remove all the placeholder values, leaving only the valid indexes.

Solution:

const letters = ['a', 'b', 'a', 'c', 'a'];
const target = 'a';

const indexes = letters
.map((element, index) => (element === target ? index : null))
.filter(index => index !== null);

console.log(indexes); // Output: [0, 2, 4]

Conclusion

For finding all indexes of an element in an array, modern JavaScript offers several effective solutions.

  • The reduce() method is the recommended functional best practice. It is concise, declarative, and encapsulates the logic in a single, fluent operation.
  • The forEach() loop is a perfectly valid and highly readable imperative alternative.
  • The map().filter() chain is a clever but less direct approach that is generally not recommended over the other two methods for this specific task.