mirror of https://gitlab.com/curben/blog
163 lines
4.2 KiB
Markdown
163 lines
4.2 KiB
Markdown
---
|
|
title: Remove duplicate objects in an array - JavaScript
|
|
excerpt: When all objects have the same keys
|
|
date: 2020-07-31
|
|
tags:
|
|
- javascript
|
|
---
|
|
|
|
Let's say you have an array of objects with duplicate entries:
|
|
|
|
``` js
|
|
const input = [
|
|
{ name: 'lorem', item: 'ipsum' },
|
|
{ name: 'per', item: 'doming' },
|
|
{ name: 'dolor', item: 'lorem' },
|
|
{ name: 'usu', item: 'pericula' },
|
|
{ name: 'per', item: 'doming' },
|
|
{ item: 'doming', name: 'per' },
|
|
{ name: 'dolor', item: 'lorem' },
|
|
{ name: 'quem', item: 'graece' },
|
|
{ item: 'graece', name: 'quem' },
|
|
{ name: 'sonet', item: 'labitur' }
|
|
];
|
|
```
|
|
|
|
A usual way of removing the duplicate objects is to use [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) and insert each entry into a [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Remove_duplicate_elements_from_the_array) then convert back to array. This approach can work if the keys are in the same order, but notice that input has two objects with different order than the rest:
|
|
|
|
{% codeblock lang:js mark:7,10 %}
|
|
const input = [
|
|
{ name: 'lorem', item: 'ipsum' },
|
|
{ name: 'per', item: 'doming' },
|
|
{ name: 'dolor', item: 'lorem' },
|
|
{ name: 'usu', item: 'pericula' },
|
|
{ name: 'per', item: 'doming' },
|
|
{ item: 'doming', name: 'per' },
|
|
{ name: 'dolor', item: 'lorem' },
|
|
{ name: 'quem', item: 'graece' },
|
|
{ item: 'graece', name: 'quem' },
|
|
{ name: 'sonet', item: 'labitur' }
|
|
]
|
|
{% endcodeblock %}
|
|
|
|
In this case, we can use `Object.fromEntries()` and `Object.entries()` to deal with duplicates; I discovered these functions while working on [hexojs/hexo-migrator-wordpress#89](https://github.com/hexojs/hexo-migrator-wordpress/pull/89). This involves two processes:
|
|
|
|
1. Convert an array of objects to an object.
|
|
2. Convert the object back to an array of objects.
|
|
|
|
The trick here lies with the first step because an object cannot have duplicate keys. Before we use `Object.fromEntries()`, we first remove the keys:
|
|
|
|
``` js
|
|
const stepOne = input.map(({ name, item }) => [name, item])
|
|
console.log(stepOne)
|
|
|
|
[
|
|
[ 'lorem', 'ipsum' ],
|
|
[ 'per', 'doming' ],
|
|
[ 'dolor', 'lorem' ],
|
|
[ 'usu', 'pericula' ],
|
|
[ 'per', 'doming' ],
|
|
[ 'per', 'doming' ],
|
|
[ 'dolor', 'lorem' ],
|
|
[ 'quem', 'graece' ],
|
|
[ 'quem', 'graece' ],
|
|
[ 'sonet', 'labitur' ]
|
|
]
|
|
```
|
|
|
|
I'm using Object [destructure](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) here:
|
|
|
|
``` js
|
|
input.map(({ name, item }) => [name, item])
|
|
|
|
// is equivalent to
|
|
input.map((element) => [element.name, element.item])
|
|
```
|
|
|
|
Then we pass `stepOne` to `Object.entries`:
|
|
|
|
``` js
|
|
const stepTwo = Object.entries(stepOne)
|
|
console.log(stepTwo)
|
|
|
|
{
|
|
lorem: 'ipsum',
|
|
per: 'doming',
|
|
dolor: 'lorem',
|
|
usu: 'pericula',
|
|
quem: 'graece',
|
|
sonet: 'labitur'
|
|
}
|
|
```
|
|
|
|
Now we have a de-duplicated object. Then, we use `Object.entries()` to convert it to an array:
|
|
|
|
``` js
|
|
const stepThree = Object.entries(stepTwo)
|
|
console.log(stepThree)
|
|
|
|
[
|
|
[ 'lorem', 'ipsum' ],
|
|
[ 'per', 'doming' ],
|
|
[ 'dolor', 'lorem' ],
|
|
[ 'usu', 'pericula' ],
|
|
[ 'quem', 'graece' ],
|
|
[ 'sonet', 'labitur' ]
|
|
]
|
|
```
|
|
|
|
Finally, we loop through each element to convert it back to object:
|
|
|
|
``` js
|
|
const stepFour = stepThree.map(([name, item]) => {
|
|
return { name, item }
|
|
})
|
|
|
|
console.log(stepFour)
|
|
|
|
[
|
|
{ name: 'lorem', item: 'ipsum' },
|
|
{ name: 'per', item: 'doming' },
|
|
{ name: 'dolor', item: 'lorem' },
|
|
{ name: 'usu', item: 'pericula' },
|
|
{ name: 'quem', item: 'graece' },
|
|
{ name: 'sonet', item: 'labitur' }
|
|
]
|
|
```
|
|
|
|
``` js
|
|
const stepFour = stepThree.map(([name, item]) => {
|
|
return {
|
|
name,
|
|
item
|
|
}
|
|
})
|
|
|
|
// is equivalent to
|
|
const stepFour = stepThree.map((element) => {
|
|
return {
|
|
name: element[0],
|
|
item: element[1]
|
|
}
|
|
})
|
|
```
|
|
|
|
To put everything together:
|
|
|
|
``` js
|
|
// in one-line
|
|
const output = Object.entries(Object.fromEntries(input.map(({ name, item }) => [name, item]))).map(([name, item]) => { return { name, item } })
|
|
|
|
// in a function
|
|
const dedup = (inArray) => {
|
|
return Object.entries(Object.fromEntries(input.map(({ name, item }) => {
|
|
return [name, item]
|
|
})))
|
|
.map(([name, item]) => {
|
|
return { name, item }
|
|
})
|
|
}
|
|
|
|
const output = dedup(input)
|
|
```
|