Home > front end >  How do i format this object using reduce
How do i format this object using reduce

Time:04-30

const data = [
  {
    product_id: 1245,
    product_name: "XYZ",
    price: "10.00",
    batch_number: 1,
  },
{
    product_id: 12456,
    product_name: "RST",
    price: "10.00",
    batch_number: 1,
  },
  {
    product_id: 111,
    product_name: "LMN",
    price: "10.00",
    batch_number: 2,
  },
  {
    product_id: 222,
    product_name: "PQR",
    price: "10.00",
    batch_number: 2,
  },
  {
    product_id: 456,
    product_name: "KKK",
    price: "10.00",
    batch_number: null,
  },
];

i want to format this object into an this type with add same batch number product in to product id and product name and price as combained. Is there any way to cahnge this. How do cahnge this to that expectedoutput Expected output

const output = [
  {
    product_id: "1245, 12345",
    product_name: "XYZ, RST",
    price: "20.00",
    batch_number: 1,
  },
  {
    product_id: "111, 222",
    product_name: "LMN, PQR",
    price: "20.00",
    batch_number: 2,
  },
  {
    product_id: 456,
    product_name: "KKK",
    price: "10.00",
    batch_number: null,
  },
];

CodePudding user response:

  • Group data array by batch_number property, store in a Map object holds key-value pairs.
const map = new Map(data.map(obj=>[obj.batch_number,[]]))
for (let obj of data) {
    map.set(obj.batch_number, [...map.get(obj.batch_number)??[],obj]);
}
/*
{1 => [
    {
        "product_id": 1245,
        "product_name": "XYZ",
        "price": "10.00",
        "batch_number": 1
    },
    {
        "product_id": 12456,
        "product_name": "RST",
        "price": "10.00",
        "batch_number": 1
    }
], 2 => Array(2), null => ...}
*/
  • Loop over each obj in map entries() method returns a new iterator object that contains the [key, value] pairs for each element in the Map object.
for (let [batch, objs] of map.entries())
  • Each iteration initializes an object with a batch_number property! and each group of batch_number gets their product_id, product_name and price accumulates the price to store them in variables arrValsIds, arrValsNames, prices respectively.
const object = {
        product_id: "",
        product_name: "",
        price: "",
        batch_number: batch,
      }
const arrValsIds = [];
const arrValsNames = [];
let prices = 0;
for (let obj of objs) {
    arrValsIds.push(obj.product_id);
    arrValsNames.push(obj.product_name);
    prices  = Number(obj.price);
}
  • Last not but least, push to an array object with properties product_id, product_name joined by ', ' and totalPrice with toFixed() method which formats a number using fixed-point notation.
output.push({
    product_id: arrValsIds.join(", "),
    product_name: arrValsNames.join(", "),
    price: prices.toFixed(2).toString(),
    batch_number: batch,
})

Expected output:

const data = JSON.parse('[{"product_id":1245,"product_name":"XYZ","price":"10.00","batch_number":1},{"product_id":12456,"product_name":"RST","price":"10.00","batch_number":1},{"product_id":111,"product_name":"LMN","price":"10.00","batch_number":2},{"product_id":222,"product_name":"PQR","price":"10.00","batch_number":2},{"product_id":456,"product_name":"KKK","price":"10.00","batch_number":null}]');

const map = new Map(data.map(obj=>[obj.batch_number,[]]))
for (let obj of data) {
    map.set(obj.batch_number, [...map.get(obj.batch_number)??[],obj]);
}

const output = [];
for (let [batch, objs] of map.entries()) {
    const object = {
                product_id: "",
                product_name: "",
                price: "",
                batch_number: batch,
              }
    const arrValsIds = [];
    const arrValsNames = [];
    let totalPrice = 0;
    for (let obj of objs) {
        arrValsIds.push(obj.product_id);
        arrValsNames.push(obj.product_name);
        totalPrice  = Number(obj.price);
    }
    output.push({
        product_id: arrValsIds.join(", "),
        product_name: arrValsNames.join(", "),
        price: totalPrice.toFixed(2).toString(),
        batch_number: batch,
    })
}
console.log(output);

CodePudding user response:

The snippet below first categorizes the products by batch_id. Then it combines the data of all the products in each batch_id. See comments.

const data = [{
    product_id: 1245,
    product_name: "XYZ",
    price: "10.00",
    batch_number: 1,
  },
  {
    product_id: 12456,
    product_name: "RST",
    price: "10.00",
    batch_number: 1,
  },
  {
    product_id: 111,
    product_name: "LMN",
    price: "10.00",
    batch_number: 2,
  },
  {
    product_id: 222,
    product_name: "PQR",
    price: "10.00",
    batch_number: 2,
  },
  {
    product_id: 456,
    product_name: "KKK",
    price: "10.00",
    batch_number: null,
  },
];

// This is a helper function that creates a key on the map if it doesn't exist
const mapGetOrSet = (map, key, getValue) => {
  if (map.has(key)) return map.get(key)
  const value = getValue()
  map.set(key, value)
  return value
}

const transform = data => {
  // Use a Map
  const productsByBatch = new Map()
  // Put each product into a batch
  data.forEach(obj => {
    const products = mapGetOrSet(productsByBatch, obj.batch_number, () => [])
    products.push(obj)
  })
  // Transform the map into the format the question wants
  return [...productsByBatch].map(([batchNumber, products]) => ({
  batch_number: batchNumber,
  // Get the product_id of all products in the batch and turn them into 1 comma seperated string using Array.prototype.join()
  product_id: products.map(({ product_id }) => product_id).join(),
  // Same thing as id
  product_name: products.map(({ product_name }) => product_name).join(),
  price: products
    // Turn string into number for addition 
    .map(({ price }) => parseFloat(price))
    // Add every price
    .reduce((total, productPrice) => total   productPrice)
  }))
}

console.log(transform(data))

The only difference from the output format is that price is a number instead of "25.00".

CodePudding user response:

Presented below is one possible way (using ".reduce()") to achieve the desired objective.

Code Snippet

const groupByBatch = arr => (
  Object.values(              // extract the "values" array from intermediate result obj
    arr.reduce(               // use ".reduce()" to iterate thru the data
      (acc, obj) => {         // "acc" is the accumulator / aggregator
        // check if batch_number already present in "acc"
        let currObj = acc[obj.batch_number] ?? false;
        // if found, concat "obj" props to existing ones (ie, "currObj" props)
        // else, simply populate "acc" with "obj" props
        acc[obj.batch_number] = currObj
        ? {
          product_id: `${currObj.product_id.toString()}, ${obj.product_id.toString()}`,
          product_name: `${currObj.product_name}, ${obj.product_name}`,
          price: ( currObj.price    obj.price).toString(),
          batch_number: obj.batch_number
        } : {
          product_id: obj.product_id.toString(),
          product_name: obj.product_name,
          price: obj.price,
          batch_number: obj.batch_number
        };
        return acc;           // return the accumulator/aggregator "acc"
      },
      {}                      // initialize "acc" to empty-object
    )
  )
);

const data = [{
    product_id: 1245,
    product_name: "XYZ",
    price: "10.00",
    batch_number: 1,
  },
  {
    product_id: 12456,
    product_name: "RST",
    price: "10.00",
    batch_number: 1,
  },
  {
    product_id: 111,
    product_name: "LMN",
    price: "10.00",
    batch_number: 2,
  },
  {
    product_id: 222,
    product_name: "PQR",
    price: "10.00",
    batch_number: 2,
  },
  {
    product_id: 456,
    product_name: "KKK",
    price: "10.00",
    batch_number: null,
  },
];

console.log('group data by batch: ', groupByBatch(data));
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments added to the snippet above.

  • Related