How to Filter Unique Objects by a Property Value in JavaScript
May 18 2025
TLDR
1.const getUniqueBy = (arr, prop) => {2. const seen = new Set();3.4. return arr.filter(item => {5. const value = item[prop];6. if (seen.has(value)) {7. return false;8. }9. seen.add(value);10. return true;11. });12.}
Usage
1.const users = [2. { id: 1, name: 'John', age: 30 },3. { id: 2, name: 'Jane', age: 25 },4. { id: 3, name: 'John', age: 40 }, // Duplicate name5. { id: 4, name: 'Bob', age: 35 }6.];7.8.const uniqueByName = getUniqueBy(users, 'name');9.10.// Result:11.// [12.// { id: 1, name: 'John', age: 30 },13.// { id: 2, name: 'Jane', age: 25 },14.// { id: 4, name: 'Bob', age: 35 }15.// ]
Filter Unique Objects Using Set and Filter: using Set()
When working with arrays of objects in JavaScript, we often need to filter out duplicate objects based on the value of a specific property. Unlike simple arrays where we can use a Set
directly, objects require a bit more work since they are compared by reference, not by value. Let's say we have this data:
1.const users = [2. { id: 1, name: 'John', age: 30 },3. { id: 2, name: 'Jane', age: 25 },4. { id: 3, name: 'John', age: 40 }, // Duplicate name5. { id: 4, name: 'Bob', age: 35 }6.];
The most efficient approach is to combine Set
to track which property values we've already seen. Then use the filter()
method to create a new array with only the unique objects.
1.2.const getUniqueBy = (arr, prop) => {3. // Create a Set to track unique property values4. const seen = new Set();5.6. return arr.filter(item => {7. const isDuplicate = seen.has(user.name); // This is O(1) check vs O(n) for find()8. if (isDuplicate) {9. return false; // Skip this item because it's a duplicate10. }11. seen.add(value);12. return true;13. });14.};15.16.const uniqueByName = getUniqueBy(users, 'name');17.
The filter()
method creates a new array with items that pass the test. In this case, we only keep an item if its property value hasn't been seen before.
Time: O(n) for the filter()
method and O(1) for the Set()
object.
Space: O(n) for the Set
object.
Alternative 1: Map and Object.values()
Another approach uses Map
to keep the last instance of each unique value:
1.const getUniqueByMap = (arr, prop) => {2. const map = new Map();3.4. arr.forEach(item => {5. map.set(item[prop], item);6. });7.8. return Array.from(map.values());9.};10.11.const users = [12. { id: 1, name: 'John', age: 30 },13. { id: 2, name: 'Jane', age: 25 },14. { id: 3, name: 'John', age: 40 }, // Duplicate name15. { id: 4, name: 'Bob', age: 35 }16.];17.18.const uniqueUsers = getUniqueByMap(users, 'name');19.// Now keeps the LAST John (age 40) instead of the first
This approach differs slightly in that it keeps the last occurrence of each unique property value instead of the first.
Time: O(n) for the forEach()
method and O(1) for the Map()
object.
Space: O(n) for the Map
object.
Alternative 2: the reduce() Method
We can also solve this problem using the reduce()
method, which is useful when you want more control over how duplicates are handled:
1.const getUniqueByReduce = (arr, prop) => {2. return arr.reduce((acc, current) => {3. const isDuplicate = acc.find(item => item[prop] === current[prop]);4. if (!isDuplicate) {5. return acc.concat([current]);6. }7. return acc;8. }, []);9.};10.11.const uniqueUsers = getUniqueByReduce(users, 'name');
Time: O(n) for the reduce()
method and O(n) for the find()
method. Combined this is O(n^2) because the find()
method has to traverse the array for each item in the acc
array.
Space: O(n) for the acc
array.
Alternative 3: the .find() method
You can also use the find()
method to check for duplicates:
1.const getUniqueByFind = (arr, prop) => {2. return arr.filter((item, index) => {3. return arr.findIndex(obj => obj[prop] === item[prop]) === index;4. }5.};6.const uniqueUsers = getUniqueByFind(users, 'name');
This method checks if the index of the first occurrence of the property value is the same as the current index. If it is, we keep the item. Otherwise, we skip it. This is less efficient than using a Set
because it has to traverse the array multiple times.
Time: O(n) for the filter()
method and O(n) for the find()
method. Combined this is O(n^2) because the find()
method has to traverse the array for each item in the arr
array.
Space: O(n) for the arr
array.
Alternative 4: Using a Plain Object
You can also use a plain object to track unique values:
1.const getUniqueByObject = (arr, prop) => {2. const seen = {};3. return arr.filter(item => {4. const value = item[prop];5. if (seen[value]) {6. return false; // Skip this item because it's a duplicate7. }8. seen[value] = true;9. return true;10. }11.};12.const uniqueUsers = getUniqueByObject(users, 'name');
This method is similar to the Set
approach, but it uses a plain object to track seen values. This is less efficient than using a Set
because it has to convert the property value to a string, which can be slower for large arrays.
Time: O(n) for the filter()
method and O(1) for the Object
object.
Space: O(n) for the Object
object.
Alternative 5: Lodash's uniqBy
If you're using Lodash, you can use the uniqBy()
method, which is a convenient way to achieve the same result:
1.import { uniqBy } from 'lodash';2.const uniqueUsers = uniqBy(users, 'name');
This method is very efficient and easy to use, but it does require including the Lodash library in your project.
Time: O(n) for the uniqBy()
method.
Space: O(n) for the uniqBy()
method.
Performance Considerations
The Set
and Map
methods are generally the most efficient for filtering unique objects by property value. The reduce()
and find()
methods can be less efficient due to their O(n^2) time complexity.