2

Basically I want to group the object which has same value of key.

const dupObj = [
  {
    "uuid": "",
    "quantity": 0,
    "distributeStoreUuid": "",
    "distributeStore__acceptanceTaskDetailsUuid": "",
    "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022",
  },
  {
    "uuid": "",
    "quantity": 3,
    "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022",
  }
 ]

and here is the expected result

[
 {
   "uuid": "",
   "quantity": 3,
   "distributeStoreUuid": "",
   "distributeStore__acceptanceTaskDetailsUuid": "",
   "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022",
 }
]

I'm experimenting with ES6 Set and here what I have so far

const uniKeys = [...(new Set(dupObj.map(({ acceptanceTaskUuid }) => acceptanceTaskUuid)))];

Any idea? Thanks in advance

Muhaimin CS
  • 195
  • 2
  • 19
  • same value of key is which column?acceptanceTaskUuid or uuid or distributeStoreUuid or acceptanceTaskUuid? – xianshenglu Feb 08 '18 at 06:48
  • Sorry forgot to mention key. It's `acceptanceTaskUuid` – Muhaimin CS Feb 08 '18 at 06:49
  • 1
    What is the logic when you have the same property but different values for the same object (`quantity` in your example)? – xander Feb 08 '18 at 06:50
  • it will store the latter. The earlier quantity discarded – Muhaimin CS Feb 08 '18 at 06:51
  • 1
    Please provide a bit more extensive input (with maybe 4, 5 entries) and desired output for it. – trincot Feb 08 '18 at 06:53
  • You could use a Map (or plain JS object) with the key being your id and value the object and then use [Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) to merge duplicate objects together. – xander Feb 08 '18 at 06:54
  • @xanderhow do merge using map and return new by Object.assign()? Not really sure how I go about it – Muhaimin CS Feb 08 '18 at 06:56
  • See my answer below for a working example – notrota Feb 08 '18 at 07:05

5 Answers5

2

The following code should work:

const dedupe = originalArray => originalArray.reduce((array, obj) => {
  const index = array.findIndex(item => item.acceptanceTaskUuid === obj.acceptanceTaskUuid)
    
  // if there already is no other acceptance task uuid
  // then append the obj to the array else add the quantities together
  return index === -1 ? [...array, obj] : Object.assign([], array, {
    [index]: Object.assign({}, array[index], obj)
  })
}, [])

console.log(dedupe([
  {
    "uuid": "",
    "quantity": 0,
    "distributeStoreUuid": "",
    "distributeStore__acceptanceTaskDetailsUuid": "",
    "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022",
  },
  {
    "uuid": "",
    "quantity": 3,
    "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022",
  },
  {
    "uuid": "",
    "quantity": 4,
    "acceptanceTaskUuid": "foobar"
  },
  {
    "uuid": "",
    "quantity": 13,
    "acceptanceTaskUuid": "foobarbaz",
  },
  {
    "uuid": "",
    "quantity": 6,
    "acceptanceTaskUuid": "foobar",
  },
]))

The findIndex function returns the index of the first item in the array which matches the condition. Basically the code above starts with an empty array, loops over the original array (reduce) and finds the index of the item with the same acceptance task uuid as the current object each iteration. If there is a duplicate then it adds the quantities together, else it just appends the new item to the array

EDIT: Made Immutable

notrota
  • 1,048
  • 10
  • 21
1

You can reduce the array into a Map. On a each pass, get the object with the same acceptanceTaskUuid from the Map, or use an empty object, assign this to current. Use forEach to iterate the array's object (o) entries, and check if the property is a number in current, and add it, or assign it if not. Then spread the Map values to get an array:

const dupObj = [{"uuid":"","quantity":1,"distributeStoreUuid":"","distributeStore__acceptanceTaskDetailsUuid":"","acceptanceTaskUuid":"acabb997-fc06-47ba-ae29-d7aea9a6a022"},{"uuid":"","quantity":3,"acceptanceTaskUuid":"acabb997-fc06-47ba-ae29-d7aea9a6a022"}]

const uniques = [...dupObj.reduce((m, o) => {
  const current = m.get(o.acceptanceTaskUuid) || {}

  Object.entries(o).forEach(([key, value]) => 
    current[key] = typeof current[key] === 'number' ? current[key] + value : value)

  return m.set(o.acceptanceTaskUuid, current)
}, new Map()).values()]

console.log(uniques)
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
0

You can use array#reduce and store object on the acceptanceTaskUuid key, if a duplicate object appears, merge them using Object.assign. Then extract the values using Object.values().

const dupObj = [ { "uuid": "", "quantity": 0, "distributeStoreUuid": "", "distributeStore__acceptanceTaskDetailsUuid": "", "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022", }, { "uuid": "", "quantity": 3, "acceptanceTaskUuid": "acabb997-fc06-47ba-ae29-d7aea9a6a022"} ],
      result = Object.values(dupObj.reduce((r, o) => {
        r[o.acceptanceTaskUuid] = Object.assign(r[o.acceptanceTaskUuid] || {}, o);
        return r;
      }, {}));
console.log(result);
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51
0

You could use a Map (or plain JS object) with the key being your id and value the object and then use Object.assign() to merge duplicate objects together.

This is a simple loop algorithm without any fancy reduce or mapping operation, it should be simple to understand.

let map = new Map();
for (let obj of dupObj) {
    if (map.has(obj.acceptanceTaskUuid))
        map.set(obj.acceptanceTaskUuid, Object.assign(map.get(obj.acceptanceTaskUuid), obj)); // merge
    else
        map.set(obj.acceptanceTaskUuid, obj);
}

// map.values() return an iterator, not an array
for (let obj of map.values()) {
    console.log(obj);
}
xander
  • 1,780
  • 9
  • 16
  • @GuyWhoKnowsStuff It's not adding it takes the latest values as OP explained it? His comment was "it will store the latter. The earlier quantity discarded". – xander Feb 08 '18 at 07:13
-2

Why not using lodash, so easy, so simple.

https://lodash.com/docs/4.17.5#filter

Gal Tamir
  • 77
  • 6