0

I have array of objects like this,

       let data = [
        { id: 1, name: 'a' },
        { id: 1, name: 'b'},
        { id: 1, name: 'a'},
        { id: 2, name: 'a'},
        { id: 2, name: 'b'},
        { id: 3, name: 'c'},
        { id: 3, name: 'c'}
       ]

I am trying to achieve unique combination of id and name, so expected output should be like,

output
    [   
        { id: 1, name: 'a'},
        { id: 1, name: 'b'},
        { id: 2, name: 'a'},
        { id: 2, name: 'b'},
        { id: 3, name: 'c'}
    ]

I have tried Set method but could not do it for key, value pair. Please could someone help. Thanks Edit- 1 Most solutions have array of string, number or object with one key-value pair. I have two key-value pairs in object.

lorem_ipsum
  • 43
  • 1
  • 7
  • 1
    Please add the code you've attempted to your question as a [mcve]. – Andy Nov 17 '22 at 15:08
  • Does this answer your question? [How to remove all duplicates from an array of objects?](https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects) – Ivar Nov 17 '22 at 15:17
  • Does this answer your question? [Remove duplicate values from JS array](https://stackoverflow.com/questions/9229645/remove-duplicate-values-from-js-array) – JaRoMaster Nov 17 '22 at 15:18
  • 1
    "_I have two key-value pairs in object._" - [So does this question](https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects). – Ivar Nov 17 '22 at 15:27

4 Answers4

1

You can actually use Set for it, you just have to use combination of values that identifies if it is unique.

let data = [
        { id: 1, name: 'a' },
        { id: 1, name: 'b'},
        { id: 1, name: 'a'},
        { id: 2, name: 'a'},
        { id: 2, name: 'b'},
        { id: 3, name: 'c'},
        { id: 3, name: 'c'}
       ]
       
const nodup = new Set();
data.forEach(item => nodup.add(`${item.id}-${item.name}`));
console.log(Array.from(nodup))
let uniqueData = Array.from(nodup).map(item => {
    const data = item.split('-')
    return {id: data[0], name: data[1]};
});
console.log(uniqueData);

After this script, if you want to have array with objects with id and name again, you can simply create it from the result.

libik
  • 22,239
  • 9
  • 44
  • 87
1

let data = [
        { id: 1, name: 'a' },
        { id: 1, name: 'b'},
        { id: 1, name: 'a'},
        { id: 2, name: 'a'},
        { id: 2, name: 'b'},
        { id: 3, name: 'c'},
        { id: 3, name: 'c'}
       ]
const unique_combos= (arr1) => {
const returned_array = []
arr1.map(element => {
    if (!(returned_array.find(e=>e?.id === element?.id && e?.name === element.name)))
        returned_array.push(element);
})

return (returned_array);
}

console.log(unique_combos(data))

I know it is not the best way to merge arrays but if that's the only case you want to handle. the above function will handle it for you.

Moussa Bistami
  • 929
  • 5
  • 15
  • Not entirely sure you posted this answer under the correct question. – Andy Nov 17 '22 at 15:20
  • Fixed the answer should work as your output expects ;) – Moussa Bistami Nov 17 '22 at 15:23
  • What I'm doing is that I'm creating a new array and fill it with using combinations if the combination of id and name already exists it skips it otherwise it will be pushed to the returned array! – Moussa Bistami Nov 17 '22 at 15:24
  • My bad I fixed it again now it is working as you really expect test it. added snippet nvm – Moussa Bistami Nov 17 '22 at 15:27
  • The only "negative" about this solution is that it is `O(n^2)`, therefore will perform quite CPU heavy once you get significant number (i.e. more than 1000) items. – libik Nov 17 '22 at 15:37
  • @libik yes but I don't believe he is working on a performance think and 1000 items wouldn't be an issue of performance maybe on over 5k since the objects are quite small ;) – Moussa Bistami Nov 17 '22 at 15:38
  • @Mbistami - 5k items will cause about 25 million iterations, which have significant impact on CPU whenever this alghorithm is called. – libik Nov 17 '22 at 15:41
0

If you want a new array of objects (rather than mutating/deleting objects from the array) you can dedupe the array in one iteration with reduce, and a Set (or an array, whatever takes your fancy).

const data=[{id:1,name:"a"},{id:1,name:"b"},{id:1,name:"a"},{id:2,name:"a"},{id:2,name:"b"},{id:3,name:"c"},{id:3,name:"c"}];

// Create a set to hold the keys
const keys = new Set();

// `reduce` over the data array, initialising the
// accumulator to an empty array.
const out = data.reduce((acc, obj) => {

  // Destructure the id and name from each object
  const { id, name } = obj;

  // Create a key
  const key = `${id}-${name}`;

  // If the key exists in the set return the
  // accumulator immediately
  if (keys.has(key)) return acc;

  // Otherwise add the key to the set,
  // add the object to the accumulator, and
  // return it for the next iteration
  keys.add(key);
  return [...acc, obj];

}, []);

console.log(out);

Additional documentation

If you want to remove objects from the array (mutation) you can use the same principle but just splice the objects from the array instead.

const data=[{id:1,name:"a"},{id:1,name:"b"},{id:1,name:"a"},{id:2,name:"a"},{id:2,name:"b"},{id:3,name:"c"},{id:3,name:"c"}];

const keys = new Set();

for (let i = 0; i < data.length; ++i) {
  const { id, name } = data[i];
  const key = `${id}-${name}`;
  if (keys.has(key)) data.splice(i, 1);
  keys.add(key);
}

console.log(data);
Andy
  • 61,948
  • 13
  • 68
  • 95
-2

Here's a much cleaner solution for ES6 that I see isn't included here. It uses the Set and the spread operator: ...

var a = [1, 1, 2];

[... new Set(a)]

Which returns [1, 2]

Dhinesh Kumar
  • 119
  • 1
  • 6