Profer
Profer

Reputation: 643

Get unique values from array of objects using reduce function

I have an array of objects

const data = [{
    productId: 7000254,
    quantity: 1
}, {
    productId: 7000255,
    quantity: 1
}, {
    productId: 7000256,
    quantity: 1
}, {
    productId: 7000257,
    quantity: 1
}, {
    productId: 7000254,
    quantity: 1
}];

I need to get unique values from it using the reduce function.

I made it using below code

data.map((rp) => {
      if (products.map(({ productId }) => productId).indexOf(rp.productId) === -1) {
        products.push({ productId: parseInt(rp.productId), quantity: 1 })
      }
    })

but as you can see it's a lengthy process because I have to iterate over the array multiple times. So is there any way using reduce function?

var unique = data.reduce((a, b ,c,d) => {
  if (a.map(({productId}) => productId).indexOf(b.productId) === -1) {
    return [a,b]
  }
})
console.log(unique)

Expected output

0: {productId: 7000254, quantity: 1}
1: {productId: 7000255, quantity: 1}
2: {productId: 7000256, quantity: 1}
3: {productId: 7000257, quantity: 1}

Upvotes: 0

Views: 2302

Answers (3)

Profer
Profer

Reputation: 643

Best way to do this without iterating multiple times is to use reduce something like this

const output = data.reduce((pv, cv) => (
  pv.array.indexOf(cv.productId) === -1) // new value
    ? {
        array: [...pv.array, cv.productId],
        output: [...pv.output, cv]
      }
    : pv
), { array: [], output: [] })

console.log({ output })

Upvotes: 0

Nitheesh
Nitheesh

Reputation: 19986

Array.reduce implementation.

Logic

  • Loop through the array.
  • Before pushing that to accumulator, verify there is aleady a node present in the accumulator.
  • If a node exist, dont push, or else push it to accumulator.

const data = [{
  productId: 7000254,
  quantity: 1
}, {
  productId: 7000255,
  quantity: 1
}, {
  productId: 7000256,
  quantity: 1
}, {
  productId: 7000257,
  quantity: 1
}, {
  productId: 7000254,
  quantity: 1
}];
const output = data.reduce((acc, curr) => {
  const matchingNode = acc.find(node => node.productId === curr.productId);
  if(!matchingNode) {
    acc.push(curr);
  }
  return acc;
}, []);
console.log(output)

Upvotes: 0

DecPK
DecPK

Reputation: 25408

You can efficiently achieve this result using filter and Set.

const data = [{
    productId: 7000254,
    quantity: 1,
  },
  {
    productId: 7000255,
    quantity: 1,
  },
  {
    productId: 7000256,
    quantity: 1,
  },
  {
    productId: 7000257,
    quantity: 1,
  },
  {
    productId: 7000254,
    quantity: 1,
  },
];

const set = new Set();
const result = data.filter((o) => {
  if (set.has(o.productId)) return false;
  set.add(o.productId);
  return true;
});

console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */

.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}

Upvotes: 2

Related Questions