Get the unique properties of objects in a JavaScript array

By

Learn how to extract the unique values of a property from an array of objects in JavaScript, combining map() with a Set and the spread operator.

~~~

To get the unique values of a property from an array of objects, map the array to that property, pass the result through a Set to drop the duplicates, and spread it back into an array. One line does it all.

Suppose you have a bills array with this content:

const bills = [
  { date: '2018-01-20', amount: '220', category: 'Electricity' },
  { date: '2018-01-20', amount: '20', category: 'Gas' },
  { date: '2018-02-20', amount: '120', category: 'Electricity' }
]

and you want to extract the unique values of the category attribute of each item in the array. Maybe to build a filter dropdown, or a list of chart labels.

Here’s what you can do:

const categories = [...new Set(bills.map(bill => bill.category))]
// ['Electricity', 'Gas']

How does this work?

Let’s break the line into its three steps.

First, map() builds a new array containing just the category value of each bill:

bills.map(bill => bill.category)
// ['Electricity', 'Gas', 'Electricity']

Set is a data structure that JavaScript got in ES6. It’s a collection of unique values. When we create a Set from that array, the duplicate 'Electricity' is dropped automatically.

... is the spread operator, which expands the Set values back into an array. We need this last step because a Set is not an array, so it has no map(), no filter(), and you can’t index into it with categories[0].

Alternatively, you can use Array.from(), which does the same conversion:

const categories = Array.from(new Set(bills.map(bill => bill.category)))

Both versions produce the same result. Pick the one you find more readable.

Watch out for typos in the property name

If you misspell the property, JavaScript won’t complain. Accessing a property that doesn’t exist returns undefined, so map() builds an array full of undefined, and the Set collapses them into one:

const categories = [...new Set(bills.map(bill => bill.categry))]
// [undefined]

No error, just a silently wrong result. If you get [undefined] where you expected real values, check the spelling of the property first.

One last note: this trick works because the values are strings. Sets compare primitives by value, so duplicate strings and numbers get removed. If the property holds objects, they’re compared by reference, and two objects with identical content both stay in.

~~~

Related posts about js: