0

I am trying to remove duplicate from an array of object in Javascript. Below is the code which doesnot work, it is creating Array of map of size 4.

let arr = [{id: 32, name: 'Name1', age: 88},
  {id: 33, name: 'Name2', age: 88},
  {id: 32, name: 'Name3', age: 88},
  {id: 1, name: 'Sam', age: 88},
  {id: 33, name: 'Name2', age: 88},
  {id: 2, name: 'Tom', age: 88}
];

console.log(arr)

let mp1 = new Map();
let uniqueElements = arr.map( obj => mp1.set(obj.id, obj))

console.log(uniqueElements);
Andy
  • 61,948
  • 13
  • 68
  • 95
Ritz
  • 11
  • 4
  • 2
    There are 2 elements in `arr` with `id` 32. First with `name` as `Name1`, next `Name3`. When you eliminate duplicate `id` 32 - which one of these two `name`s needs to be retained? – jsN00b Mar 03 '22 at 04:24
  • Have you checked this StackOverflow answer that has the same question? https://stackoverflow.com/questions/27030/comparing-arrays-of-objects-in-javascript – Micah Johnson Mar 03 '22 at 04:28
  • 1
    Can you please [edit] the question to explain why 4 is the wrong answer for counting unique IDs? Or maybe explain what you mean by "duplicates" - the code shown seems to say "duplicates are objects with the same `id`" - possibly you wanted something else. – Alexei Levenkov Mar 03 '22 at 04:28
  • My understand is since it is map with key value, last one should overwrite the previous one. Hence {id: 32, name: 'Name3', age: 88} should be present in final – Ritz Mar 03 '22 at 04:29
  • _since it is map with key value, last one should overwrite the previous one_ - we are able to choose which one needs to stay and which ones will need to be discarded as duplicate. It may be possible to use `.reduce()` to achieve the desired objective. – jsN00b Mar 03 '22 at 04:36
  • 1
    You don't even need reduce. A simple for/loop will work. OP is really complicating things using `map` and `set` (imo). – Andy Mar 03 '22 at 04:37
  • @Andy, agreed. In several situations, `.reduce()` may be replaced with a `for` loop - as they are both constructs to iterate through the array. – jsN00b Mar 03 '22 at 04:39
  • Thanks all for reply. I first tried with reduce. code is below - ``` let arr = [{id: 32, name: 'Name1', age: 88}, {id: 33, name: 'Name2', age: 88}, {id: 32, name: 'Name3', age: 88}, {id: 1, name: 'Sam', age: 88}, {id: 33, name: 'Name2', age: 88}, {id: 2, name: 'Tom', age: 88}] let uniques = arr.reduce((mp1, obj) =>{mp1.set(obj.id, obj)}, new Map()) ``` I was then getting error - Uncaught TypeError: Cannot read properties of undefined (reading 'set') – Ritz Mar 03 '22 at 04:52

2 Answers2

1

Below snippet may be one possible implementation to achieve the desired objective:

const discardDupeIdElements = arr => (
  Object.values(
    arr.reduce(
      (fin, itm) => ({
        ...fin,
        [itm.id]: itm
      }), {}
    )
  )
);

var origArr = [{
    id: 32,
    name: 'Name1',
    age: 88
  },
  {
    id: 33,
    name: 'Name2',
    age: 88
  },
  {
    id: 32,
    name: 'Name3',
    age: 88
  },
  {
    id: 1,
    name: 'Sam',
    age: 88
  },
  {
    id: 33,
    name: 'Name2',
    age: 88
  },
  {
    id: 2,
    name: 'Tom',
    age: 88
  }
];

console.log(discardDupeIdElements(origArr));

Note

This will always keep the last element of a set of duplicates and ignore all earlier ones. Such as for id 32, it will keep the element with name = Name3 and discard Name2.

Fixing the OP's code:

const arr = [{id: 32, name: 'Name1', age: 88},
  {id: 33, name: 'Name2', age: 88},
  {id: 32, name: 'Name3', age: 88},
  {id: 1, name: 'Sam', age: 88},
  {id: 33, name: 'Name2', age: 88},
  {id: 2, name: 'Tom', age: 88}
];

// console.log(arr);
// commented-out for easier viewing of the output

const mp1 = new Map();      // declared a map

arr.forEach(obj => mp1.set(obj.id, obj));
// used .forEach to iterate through the array
// and update the map

const uniqueElements = [...mp1.values()];
// used spread operator to extract 
// the values of the map into an array

console.log(uniqueElements);
// console.log the unique elements

Note

Where possible, used const rather than let.

jsN00b
  • 3,584
  • 2
  • 8
  • 21
1

map returns the new array with the same length of the calling array

For accumulated value (here is mp1), you should use reduce

let uniqueElements = arr.reduce(
  (mp1, obj) => mp1.set(obj.id, obj),
  new Map()
)

let arr = [
  { id: 32, name: 'Name1', age: 88 },
  { id: 33, name: 'Name2', age: 88 },
  { id: 32, name: 'Name3', age: 88 },
  { id: 1, name: 'Sam', age: 88 },
  { id: 33, name: 'Name2', age: 88 },
  { id: 2, name: 'Tom', age: 88 },
]

console.log(arr)
let uniqueElements = arr.reduce((mp1, obj) => mp1.set(obj.id, obj), new Map())
console.log(uniqueElements)
hgb123
  • 13,869
  • 3
  • 20
  • 38
  • I first tried with reduce function only. Code is below - ``` let arr = [{id: 32, name: 'Name1', age: 88}, {id: 33, name: 'Name2', age: 88}, {id: 32, name: 'Name3', age: 88}, {id: 1, name: 'Sam', age: 88}, {id: 33, name: 'Name2', age: 88}, {id: 2, name: 'Tom', age: 88}] let uniques = arr.reduce((mp1, obj) =>{mp1.set(obj.id, obj)}, new Map()) ``` But then I was getting error - Uncaught TypeError: Cannot read properties of undefined (reading 'set') – Ritz Mar 03 '22 at 04:47