3

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);
mheavers
  • 29,530
  • 58
  • 194
  • 315

2 Answers2

4

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)
Spectric
  • 30,714
  • 6
  • 20
  • 43
1

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);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209