I have two lists:
let originalDocs = [
{
id: "sara",
date: new Date("01/01/2022")
},
{
id: "vic",
date: new Date("10/26/2020")
}
];
let newDocs = [
{
id: "vic",
date: new Date("01/02/2022")
},
{
id: "raul",
date: new Date("05/05/2021")
}
];
I need to mix both lists, ordering by date (in descending order) and without repetitions.
In order to do that, I have decided to:
- Delete the set of elements of the original array that are included in the new array (I mean, deleting the intersection) without modifying the original array.
- Mix the resulted array ordering by date.
This is my current code:
function removeIntersection(originalDocs, newDocs) {
return originalDocs.filter((originalDoc) => {
const index = newDocs.findIndex(
(newDoc) => newDoc.id === originalDoc.id
);
return index === -1;
});
}
function mixInOrder(originalDocs, newDocs) {
return [...newDocs, ...originalDocs]
.sort((a, b) => b.date - a.date);
}
//
// MAIN
//
let originalDocs = [
{
id: "sara",
date: new Date("01/01/2022")
},
{
id: "vic",
date: new Date("10/26/2020")
}
];
let newDocs = [
{
id: "vic",
date: new Date("01/02/2022")
},
{
id: "raul",
date: new Date("05/05/2021")
}
];
const result = mixInOrder(
removeIntersection(originalDocs, newDocs),
newDocs
);
console.log(result);
How can I do the same in a more optimal way, I mean, without the need of merging (using the spread syntax) the list before sorting it, or deleting the intersection in O(1).
I mean, is it possible to just insert in order avoiding the copy?
CodePudding user response:
You can easily achieve the result using Set
and reduce
as:
- Create a new array by adding the
originalDocs
first and thennewDocs
afterwards. - Use
reduce
to loop over the newly created array and then filter the objects.
You can use
Set
to check for existence of a key in efficient way
- After filtering, you can then sort it accordingly.
let originalDocs = [
{
id: 'sara',
date: new Date('01/01/2022'),
},
{
id: 'vic',
date: new Date('10/26/2020'),
},
];
let newDocs = [
{
id: 'vic',
date: new Date('01/02/2022'),
},
{
id: 'raul',
date: new Date('05/05/2021'),
},
];
const set = new Set();
const result = [...originalDocs, ...newDocs].reduce((acc, curr) => {
if (!set.has(curr.id)) {
acc.push(curr);
set.add(curr.id);
}
return acc;
}, [])
.sort((a, b) => b.date - a.date);
console.log(result);
CodePudding user response:
Here's how to do this using a JS Map, where you use the id
as identifier:
let originalDocs = [
{
id: "sara",
date: new Date("01/01/2022")
},
{
id: "vic",
date: new Date("10/26/2020")
}
];
let newDocs = [
{
id: "vic",
date: new Date("01/02/2022")
},
{
id: "raul",
date: new Date("05/05/2021")
}
];
const map = new Map(originalDocs.map(el => [el.id, el]));
newDocs.forEach(el => map.set(el.id, el));
const sorted = [...map.values()].sort((a, b) => a.date - b.date);
console.log(sorted)
This overrides any originalDocs
entry with a newDocs
entry if they have the same id
.