I have an array of objects in which most of the properties may be duplicates of each other, but one value may differ:
const originalArray = [
{ id: 1, name: 'x', 'description': 'x', url: 'y' },
{ id: 2, name: 'x', 'description': 'x', url: 'z' }
]
I want to dedupe this array based on a difference of name, but retain the URL differences as an array in the deduped array:
const dedupedArray = [
{ id: 1, name: 'x', 'description': 'x', url: ['y','z'] },
]
function removeDuplicatesByProperty(keyFn, array) {
const mySet = new Set();
return array.filter(function (x) {
const key = keyFn(x),
isNew = !mySet.has(key);
if (isNew) mySet.add(key);
return isNew;
});
}
const dedupedArray = removeDuplicatesByProperty((x) => x.name, originalArray);
CodePudding user response:
You can use Array.reduce
:
const originalArray = [
{ id: 1, name: 'x', 'description': 'x', url: 'y' },
{ id: 2, name: 'x', 'description': 'x', url: 'z' }
]
const res = originalArray.reduce((a,b) => {
const found = a.find(e => e.name == b.name);
return found ? found.url.push(b.url) : a.push({...b, url:[b.url]}), a;
}, [])
console.log(res)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
Reduce the array to a Map, and merge duplicates using a mergeFn
. Convert the Map.values()
iterator back to an array using Array.from()
or array spread:
const originalArray = [
{ id: 1, name: 'x', 'description': 'x', url: 'y' },
{ id: 2, name: 'x', 'description': 'x', url: 'z' }
]
const dedupeMerge = (keyFn, mergeFn, array) => Array.from(
array.reduce((acc, o) => {
const key = keyFn(o);
if(!acc.has(key)) return acc.set(key, o);
return acc.set(key, mergeFn(acc.get(key), o));
}, new Map()).values()
);
const dedupedArray = dedupeMerge(
x => x.name,
(o1, o2) => ({ ...o1, url: [o1.url, o2.url].flat() }),
originalArray
);
console.log(dedupedArray);
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>