I recently had a problem whereby I wanted to filter objects in an array by comparing the values of nested properties of each object to see if there were duplicates.
I have tried to explain as clearly as possible the scenario below and the solution I came up with. I wondering if it's possible to improve this solution and if so, how?
Example:
let articles = [{dateAdded: "31-5-1989", readId: 123, article: { id: 1}}, {dateAdded: "31-5-1989", readId: 124, article: { id: 2}}, {dateAdded: "31-5-1989", readId: 125, article: { id: 1}}]
In this array, you can see each object has a readId
and an articleId
. The first and last objects in the array have a different readId
but a matching articleId
. We want to return every object in this array unless we have already returned an object with the same articleId
.
Here is my solution:
const removeDuplicatesbyArticleId = articles => {
let articleIdsArray = [];
let finalArray = [];
articleResponse.reading.map(element => {
if (!articleIdsArray.includes(element.article.id)) {
articleIdsArray.push(element.article.id);
finalArray.push(element);
}
});
let filteredArticleResponse = articles;
filteredArticleResponse.reading = finalArray;
return filteredArticleResponse;
};
All I'm doing here is looping through the array, checking if the articleId
exists in the articleIdsArray
and if not, pushing this onto finalArray
and then repeating before returning finalArray at the end of the loop.
This solution feels a little crude, I'd be really grateful if anyone could suggest an alternative(s) solution(s) that is easier to read, better for performance, or both!
I apologise if this is a repeat, from much searching I couldn't find a question and answer that matched my specific case.
2 Answers 2
We want to return every object in this array unless we have already returned an object with the same
articleId
.
I would use a Set
object to keep track of which articleId
values we've already used and then use .filter()
to return only the items that pass the test. Here's a runnable implementation:
let articles = [
{dateAdded: "31-5-1989", readId: 123, article: { id: 1}},
{dateAdded: "31-5-1989", readId: 124, article: { id: 2}},
{dateAdded: "31-5-1989", readId: 125, article: { id: 1}}
];
function getUniqueArticles(array) {
let ids = new Set();
return array.filter(function(item) {
if (!ids.has(item.article.id)) {
ids.add(item.article.id);
return true;
}
return false;
});
}
console.log(getUniqueArticles(articles));
Note: Your articles array does not look valid as there seems to be a missing comma here in each array element and you probably mean to have quotes around the date to make it into a string:
{dateAdded: "31-5-1989", readId: 123, article: { id: 1}}
^^^ ^^^ ^^^
-
\$\begingroup\$ thanks this is much cleaner, had seen
Set()
but for some reason didn't look into it more this is really useful thanks. I was writing the array on the fly and forgot the quotes and commas - added in now, thanks for highlighting. \$\endgroup\$Will Kempster– Will Kempster2018年07月23日 21:37:38 +00:00Commented Jul 23, 2018 at 21:37
You can use a function that removes the duplicates based on the field you want to filter for example
function removeDuplicate(arr){
let unique_array = arr.filter(function(elem, index, self) {
return index == self.map(res => res.article.id).indexOf(elem.article.id);
});
return unique_array
}