Removing Duplicates from Arrays in JavaScript Guide
Learn four ways to remove duplicate values from JavaScript arrays: Set, filter, reduce, and forEach. Compare approaches for primitives and objects.
JavaScript gives you several ways to remove duplicate values from an array. The best approach depends on whether your array contains primitives (numbers, strings) or objects, and how large the array is.
1. Set -- The Modern Standard (Primitives)
A Set is a collection that only stores unique values. Converting an array to a Set and back removes all duplicates in one shot:
const numbers = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3, 4]This works for any primitive type, and a Set can even hold a mix of different types in the same collection:
const mixed = [1, "hello", 1, "hello", true, true, null, null];
const unique = [...new Set(mixed)];
console.log(unique); // [1, "hello", true, null]Set uses the SameValueZero algorithm for comparison. It correctly handles NaN, treats +0 and -0 as equal, and works with undefined and null.
The Set approach is the shortest, fastest, and most readable. It should be your default choice for arrays of primitives.
The array passes through a Set, which silently drops duplicates. Spreading the Set back into an array gives you the result.
2. filter() with indexOf() (Works Everywhere)
Before Set became common, filter() combined with indexOf() was the standard approach:
const items = ["a", "b", "a", "c", "b"];
const unique = items.filter((item, index) => items.indexOf(item) === index);
console.log(unique); // ["a", "b", "c"]The logic: keep an element only if its first occurrence in the array is at the current index. If indexOf(item) returns an earlier index, the element is a duplicate and is filtered out.
This approach works in older environments that do not support Set, but it is O(n²) because indexOf() scans the array for each element. For large arrays, prefer Set.
3. reduce() (Flexible but Verbose)
reduce() gives you full control over the deduplication logic:
const numbers = [1, 2, 2, 3, 3, 3, 4];
const unique = numbers.reduce((acc, n) => {
if (!acc.includes(n)) {
acc.push(n);
}
return acc;
}, []);
console.log(unique); // [1, 2, 3, 4]The accumulator starts as an empty array. Each element is added only if it is not already present. This is also O(n²) due to the includes() check inside the loop.
Use reduce() only when you need custom deduplication logic that Set cannot express directly. For the basics of reduce(), see JavaScript Array Reduce Method.
4. Deduplicating Arrays of Objects
Set does not help with object arrays because objects are compared by reference:
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 1, name: "Alice" } // Same id, different object reference
];
const unique = [...new Set(users)];
console.log(unique.length); // 3 (nothing removed!)To deduplicate objects, use a Map keyed by a unique property, since a Map lets you look up and overwrite entries by that key directly:
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 1, name: "Alice" }
];
const unique = [...new Map(users.map(u => [u.id, u])).values()];
console.log(unique);
// [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]Step by step:
Map each user to a key-value pair
users.map(u => [u.id, u]) creates a two-item array for each user, pairing that user's id with the full user object.
Build a Map from those pairs
new Map(...) stores entries by key. Duplicate keys overwrite, keeping the last value.
Extract the unique objects
.values() returns an iterator over the Map's values, one per unique key.
Convert back to an array
[...spread] converts that iterator into a real array.
For deeper object comparison (matching by all properties), use a JSON-based key:
const uniqueByContent = [...new Map(
users.map(u => [JSON.stringify(u), u])
).values()];This treats objects as equal if they have the same JSON representation, regardless of which id field you consider the key. Watch out for property order: JSON.stringify() preserves key order, so two objects with identical properties written in a different order produce different strings and will not be treated as duplicates.
Performance Comparison
| Method | Complexity | Best for |
|---|---|---|
Set | O(n) | Primitives (numbers, strings) |
filter() + indexOf() | O(n²) | Legacy environments only |
reduce() + includes() | O(n²) | Custom deduplication logic |
Map by key | O(n) | Arrays of objects |
For primitives, Set is both the fastest and the shortest. For objects, Map by a unique key is the fastest. The filter() and reduce() approaches are quadratic and should only be used when Set or Map is unavailable.
Common Mistakes
Expecting Set to deduplicate objects:
const a = { id: 1 };
const b = { id: 1 };
const arr = [a, b];
console.log([...new Set(arr)].length); // 2 (Set sees two different objects)Set compares objects by reference, not by content. For object deduplication, use the Map pattern shown above.
Using Set on very large arrays without considering memory:
// Set creates an intermediate data structure
const huge = [...new Set(massiveArray)];For arrays with millions of items, the intermediate Set uses extra memory. If memory is a concern and the array is already sorted, use a single-pass loop:
function dedupeSorted(arr) {
return arr.filter((item, i) => i === 0 || item !== arr[i - 1]);
}
const sorted = [1, 1, 2, 2, 3, 3, 3];
console.log(dedupeSorted(sorted)); // [1, 2, 3]This only works on sorted arrays and is O(n) with no extra data structure.
Now that you have mastered arrays, the next section covers objects, maps, and sets where you will learn about key-value data structures and how they complement arrays.
Rune AI
Key Insights
- [...new Set(arr)] is the simplest and fastest way to deduplicate arrays of primitives.
- Set comparison uses SameValueZero, which works for primitives but not for distinct objects with the same properties.
- filter() with indexOf works for primitives but is O(n²) and slower for large arrays.
- Use a Map keyed by a unique property to deduplicate arrays of objects.
- For already-sorted arrays, a single-pass comparison approach is the most efficient.
Frequently Asked Questions
What is the fastest way to remove duplicates from an array?
Does the Set approach work for removing duplicate objects?
Can I remove duplicates from a sorted array more efficiently?
Conclusion
Removing duplicates is a common task with several good solutions. For arrays of primitives, the Set approach is the clear winner -- it is the shortest, fastest, and most readable. For arrays of objects, use a Map keyed by a unique identifier to deduplicate by that property. Understanding the tradeoffs between these approaches lets you choose the right tool for your data.
More in this topic
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.
How to Loop Through Arrays Using JS for Loops Guide
Looping through arrays is the most practical use of JavaScript for loops. Learn how to access each element by index, avoid off-by-one errors, and choose between for, for...of, and forEach.