post: dedup array of objects

This commit is contained in:
MDLeom 2020-07-31 02:20:32 +01:00
parent 911cf077ad
commit 28e2caefdc
No known key found for this signature in database
GPG Key ID: 32D3E28E96A695E8
1 changed files with 162 additions and 0 deletions

View File

@ -0,0 +1,162 @@
---
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. 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)
```