0

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}

3 Answers 3

2

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;
}

Sign up to request clarification or add additional context in comments.

7 Comments

Jeah, I would choose this over reduce. It's easier to read.
@Totati Time complexity is also O(n) as compared to reduce if used with find.
You coudl use Set with reduce too, but I'd still choose filter :D You coudl use Map too, but that would mean 2 iterations, as at the end you need to map the values back to an array.
@malarres set.has Will gives the result in constant time O(1).
nice to know @HR01M8055, I got from the spec that it required to be O(n) "as much" but I didn't know that it was implemented as O(1) source: Set objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection. 262.ecma-international.org/6.0/#sec-set-objects
|
0

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)

4 Comments

find inside reduce makes its worst time complexity to n * 2. You could have used Set here to make it O(n)
@HR01M8055 Question is regarding functionality, not regarding performace.
I totally agree with you. But If we get functionality with performance then that will be even better. What is the use of the functionality if it is not efficient. Don’t you think
@HR01M8055 Agree. We have a lot of performace optimizations. One is provided by you. Do I ned to find all he performace improvement as fix them?
0

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 })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.