I have an array of objects that looks like the following:
[
{
id: 1234
name: Name1
},
{
id: 5678
name: Name1
},
{
id: 1234
name: Name1
},
{
id: 5678
name: Name2
},
]
I want to filter out and remove the objects that have the same id AND the same name, so the expected result would look like the following:
[
{
id: 1234
name: Name1
},
{
id: 5678
name: Name1
},
{
id: 5678
name: Name2
},
]
However I am only able to filter the array of objects by unique ID and I'm not sure how to cater for the extra condition of the same name:
data.filter((value, index, self) => {
return (
self.findIndex((v) => v.id=== value.id) === index
);
});
You can simply use && to include additional criteria that needs to be met: in your example, you want both the id and name to match:
const filteredData = data.filter((value, index, self) =>
self.findIndex(v => v.id === value.id && v.name === value.name) === index
);
If you have multiple keys you want to consider and you don't want to write multiple && statements, you can simply store the keys in an array, and then use Array.prototype.every() to enforce the match:
const keys = ['id', 'name'];
const filteredData = data.filter((value, index, self) =>
self.findIndex(v => keys.every(k => v[k] === value[k])) === index
);
See proof-of-concept below:
const data = [{
id: 1234,
name: 'Name1'
},
{
id: 5678,
name: 'Name1'
},
{
id: 1234,
name: 'Name1'
},
{
id: 5678,
name: 'Name2'
},
];
const keys = ['id', 'name'];
const filteredData = data.filter((value, index, self) =>
self.findIndex(v => keys.every(k => v[k] === value[k])) === index
);
console.log(filteredData);
You can try this straight forward solution by using array.filter() method along with array.indexOf() and array.lastIndexOf()
Working Demo :
const obj = [
{
id: 1234,
name: 'Name1'
},
{
id: 5678,
name: 'Name1'
},
{
id: 1234,
name: 'Name1'
},
{
id: 5678,
name: 'Name2'
}
];
const res = obj.filter((item, index, obj) =>
obj.indexOf(item) && obj.lastIndexOf(item)
);
console.log(res);
You could extend and add another condition in your findIndex. Something like this
data.filter((value, index, self) => {
return (
self.findIndex((v) => v.id === value.id && v.name === value.name) === index
);
});
But this is time consuming. You're better of if you create a hash and use that to filter out.
data.reduce( (acc, current) => {
acc[`${current.name}#${current.id}`] = current;
return acc
}, {}).values()
What I'm doing here is to create an entry for each unique combination of name/id and then only get the values of that object.