'I want to combine the objects in the array, how should I change them?

const data = [
  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "13inch",
    optionPrice: 0,
    qty: 2,
  },
  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "15inch",
    optionPrice: 1000,
    qty: 1,
  },
]

const results = data.reduce((prev, curr) => {
  if (prev.productId === curr.productId) {
    ???
  }
  
}, []);

output

  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    option: [
      { optionName: "13inch", optionPrice: 0, qty: 2 },
      { optionName: "15inch", optionPrice: 1000, qty: 1 },
    ],
  },

If the productId is the same as the code above,

I want to remove the overlapping part of key:value, create an option object for the non-overlapping part, and create an array object for value.

I tried to solve it by using reduce, but it didn't go well, so I'm asking you a question.



Solution 1:[1]

One method is to convert array into object, and use productId as key:

const data = [
  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "13inch",
    optionPrice: 0,
    qty: 2,
  },
  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "15inch",
    optionPrice: 1000,
    qty: 1,
  },
  {
    productId: 4,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "15inch",
    optionPrice: 1000,
    qty: 1,
  },
]

const results = Object.values(data.reduce((prev, curr) => {
  if (prev[curr.productId])
  {
    const obj = prev[curr.productId];
    if (!obj.option)
    {
      obj.option = [];
      obj.option.push({optionName: obj.optionName, optionPrice: obj.optionPrice, qty: obj.qty});
      delete obj.optionName;
      delete obj.optionPrice;
      delete obj.qty;
    }
    
    prev[curr.productId].option.push({optionName: curr.optionName, optionPrice: curr.optionPrice, qty: curr.qty});
  }
  else
    prev[curr.productId] = Object.assign({}, curr);

  return prev;
  
}, {}));

console.log(results);

Solution 2:[2]

Here's a pure, functional approach which won't mutate any part of your existing array data:

function deduplicate (array) {
  const results = [];
  const idCache = new Set();

  for (const item of array) {
    // skip if we've already seen products with the same ID
    if (idCache.has(item.productId)) continue;
    idCache.add(item.productId);
    // get products with matching ID
    const items = array.filter(({productId}) => productId === item.productId);

    // if there were none, store the single product as-is and continue
    if (items.length === 0) {
      results.push({...item});
      continue;
    }

    // add initial product to others, preserving order
    items.unshift(item);
    const merged = {};

    for (const key of Object.keys(item)) {
      const values = items.map(item => item[key]);
      // if all the same value, set it on the merged object
      if (values.every(val => val === item[key])) merged[key] = item[key];
      else {
        // set to property on obj in "options" array
        for (const [idx, val] of values.entries()) {
          ((merged.options ??= [])[idx] ??= {})[key] = val;
        }
      }
    }

    results.push(merged);
  }

  return results;
}

const data = [
  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "13inch",
    optionPrice: 0,
    qty: 2,
  },
  {
    productId: 6,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "15inch",
    optionPrice: 1000,
    qty: 1,
  },
  {
    productId: 5,
    productName: "pouch",
    productPrice: 29000,
    discountRate: 19,
    optionName: "15inch",
    optionPrice: 1000,
    qty: 1,
  },
];

const result = deduplicate(data);
console.log(result);

Solution 3:[3]

Here is one way you can do it:

const data = [   {     productId: 6,     productName: "pouch",     productPrice: 29000,     discountRate: 19,     optionName: "13inch",     optionPrice: 0,     qty: 2,   },   {     productId: 6,     productName: "pouch",     productPrice: 29000,     discountRate: 19,     optionName: "15inch",     optionPrice: 1000,     qty: 1,   },   {     productId: 4,     productName: "pouch",     productPrice: 29000,     discountRate: 19,     optionName: "15inch",     optionPrice: 1000,     qty: 1,   }, ],

      output = Object.entries(
          data.reduce(
              (prev,{productId,...r}) =>
              ({...prev, [productId]: Object.entries(r).reduce(
                  (acc,[key,value]) =>
                  ({...acc, [key]: prev[productId] && prev[productId][key] ?
                      prev[productId][key] === value ? 
                      value :
                      [prev[productId][key],value] :
                      value
                  }),{})
              }),{}
          )
      )
      .map(
          ([productId,obj]) =>
          ({
              productId, 
              ...Object.entries(obj).reduce(
                  (acc,[key,value]) =>
                  !Array.isArray(value) ? 
                  ({...acc, [key]:value}) : 
                  ({...acc, option:value.map(
                      (v,i) => 
                      acc["option"] ? 
                      ({...acc["option"][i], [key]: v}) :
                      ({[key]: v}))
                  }),
              {})
          })
       );

console.log(output);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 jsejcksn
Solution 3 PeterKA