'Javascript - Remove duplicate ID from array of objects
Take the following two arrays:
const array1 = [
{
props: {
type : 'text',
id : 'item1',
name : 'item1',
value : '@item1@',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '@item2@',
},
}
];
const array2 = [
{
props: {
type: 'hidden',
id: 'item1',
name: 'item1',
value: '@item1@',
},
}
];
What I'm trying to do is concatenate them into a single array, and remove any duplicates based on the id
property. However the caveat here is that the object that does NOT have a type
of hidden
must have presidence.
So I should basically be left with the contents of array1
, as the duplicate item from array2
has the type
value of hidden
, like so:
// Result
[
{
props: {
type : 'text', // Note the type here is "text"
id : 'item1',
name : 'item1',
value : '@item1@',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '@item2@',
},
}
];
I can easily concatenate them using:
const array = array1.concat(array2);
My idea was to then use a Filter but I'm having a bit of a brain melt. Here is what I have come up with so far:
const concat = (array1, array2) => {
const array = array1.concat(array2);
const ids = [];
// Create array of ID's
for (const i in array1) {
ids.push(array1[i].props.id);
}
return array.filter((obj) => {
if (obj.props.type !== 'hidden' && ids.includes(obj.props.id)) {
return true;
}
return false;
});
};
Would using a Reduce be a better approach here?
Here is a JSFiddle of what I have so far: https://jsfiddle.net/64uprbhn/
Solution 1:[1]
You can
- Create a Map of
id => object
from the first array - Go over the second array and either
- add the item if not already in the map
- check if the current item is not
type: "hidden"
and overwrite the other one - otherwise discard the item
- Create a new array from the Map
const array1 = [
{
props: {
type : 'text',
id : 'item1',
name : 'item1',
value : '@item1@',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '@item2@',
},
},
{
props: {
type: 'hidden',
id: 'item3',
name: 'item3',
value: '@item3@',
},
}
];
const array2 = [
{
props: {
type: 'hidden',
id: 'item1',
name: 'item1',
value: '@item1@',
},
},
{
props: {
type: 'text',
id: 'item3',
name: 'item3',
value: '@item3@',
},
}
];
//1. create a map from id => object pairs
const map = new Map(array1.map(obj => [obj.props.id, obj]));
//2. go over the second array
array2.forEach(obj => {
if (!map.has(obj.props.id) //not a duplicate
|| obj.props.type !== "hidden") { //is not hidden
//insert
map.set(obj.props.id, obj);
}
});
//3. convert back into array
const merged = [...map.values()];
console.log(merged);
For the record, you can basically do the same (or pretty similar) thing using .filter
but you'll have to do a O(n)
lookup for each item. A Map ensures much faster lookups.
Solution 2:[2]
const array1 = [
{
props: {
type : 'text',
id : 'item1',
name : 'item1',
value : '@item1@',
},
},
{
props: {
type: 'hidden',
id: 'item2',
name: 'item2',
value: '@item2@',
},
}
];
const array2 = [
{
props: {
type: 'hidden',
id: 'item1',
name: 'item1',
value: '@item1@',
},
}
];
function getUnique(arr, comp) {
const unique = arr
.map(e => e[comp])
// store the keys of the unique objects
.map((e, i, final) => final.indexOf(e) === i && i)
// eliminate the dead keys & store unique objects
.filter(e => arr[e]).map(e => arr[e]);
return unique;
}
const arr = array1.concat(array2);
console.log(getUnique(arr, 'id'));
Solution 3:[3]
Here's what worked for me
const someItems = [{ id: 1 }, { id: 2 }, { id: 1 }]
function getUniqueItems(items) {
const uniqueIds = new Set(items.map((item) => item.id))
const itemsWithUniqueIds = [...uniqueIds].map(id => items.find(item => item.id === id)).filter(Boolean)
return itemsWithUniqueIds
}
console.log(getUniqueItems(someItems))
If you are using TypeScript, TS will complain about the .filter(Boolean)
. In that case just replace Boolean
with (item: any | undefined): item is any => Boolean(item)
. Of course, you can then go ahead and also replace any
with whichever type makes sense in your case.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | georg |
Solution 2 | VLAZ |
Solution 3 | maninak |