Home » Jquery » javascript – Manipulating array of objects into new array

javascript – Manipulating array of objects into new array

Posted by: admin February 22, 2020 Leave a comment

Questions:

I have the following array:

var my_json = [{
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "845",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "1002",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD3",
  PRODUCT_QUANTITY_MT: "45",
}, {
  DATE: "2020-02-02",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "20",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "10",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "230",
}]

From the above array I want to create two new arrays, for each day for each product how much was sold. The final array should look like this.

The first value would be a default value call DATE followed by each product name.

var final = [{
  title: "DATE"
}, {
  title: "PROD1"
}, { 
  title: "PROD2"
}, {
  title: "PROD3"
}]

I managed to create this by doing the following

var columns = [{ "title":"DATE" }];

$.each(my_json, function(index, element) {                         
  columns.push({ "title": element.PRODUCT_NAME })
});

The second array should be in this format:

var data = [
  [ "2020-02-01", 845", "1002" , "45"],
  [ "2020-02-02", "20", "",  "" ],
  [ "2020-02-03", "10", "230",  "" ],
];

As you can see, on Feb 1 we have a value for all products sold but on Feb 2 it’s only PROD1. Likewise on Feb 3 only PROD2 and PROD3.

Each row col should match the first array like bellow

enter image description here

desired output of two arrays as bellow

         var Array1 = [{title: "DATE"},{title: "PROD1"},{title: "PROD2"}, 
                      {title: "PROD3"}]

         var Array2 = [
                       [ "2020-02-01", 845", "1002" , "45"],
                       [ "2020-02-02", "20", "",  "" ],
                       [ "2020-02-03", "10", "230",  "" ],
                    ];
How to&Answer:

Please refer below code

var my_json = [{
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "845",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "1002",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD3",
  PRODUCT_QUANTITY_MT: "45",
}, {
  DATE: "2020-02-02",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "20",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "10",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "230",
}];
var Array1 = [{
  title: "DATE"
}];
var Array2 = [];
for (var i = 0; i < my_json.length; i++) {
  add(Array1, my_json[i].PRODUCT_NAME);
  switch (my_json[i].PRODUCT_NAME) {
    case "PROD1":
      Array2.push([my_json[i].DATE, my_json[i].PRODUCT_QUANTITY_MT, "", ""])
      break;
    case "PROD2":
      Array2.push([my_json[i].DATE, "", my_json[i].PRODUCT_QUANTITY_MT, ""])
      break;
    case "PROD3":
      Array2.push([my_json[i].DATE, "", "", my_json[i].PRODUCT_QUANTITY_MT])
      break;
  }
}

function add(arr, name) {
  const {
    length
  } = arr;
  const id = length + 1;
  const found = arr.some(el => el.title === name);
  if (!found) arr.push({
    title: name
  });
  return arr;
}

for (var i = 0; i < Array2.length; i++) {
  if (i != Array2.length - 1 && Array2[i][0] == Array2[i + 1][0]) {    
    Array2[i + 1][1] != "" ? Array2[i][1] = Array2[i + 1][1] : Array2[i][1];   
    Array2[i + 1][2] != "" ? Array2[i][2] = Array2[i + 1][2] : Array2[i][2];    
    Array2[i + 1][3] != "" ? Array2[i][3] = Array2[i + 1][3] : Array2[i][3];
    Array2.splice(i + 1, 1);
    i--;
  }
}
console.log(Array1);

console.log(Array2);

Answer:

You could get an object with the indices for the columns and reduce the given data by looking up the right row and update the value for a certain column.

var data = [{ DATE: "2020-02-01", PRODUCT_NAME: "PROD1", PRODUCT_QUANTITY_MT: "845" }, { DATE: "2020-02-01", PRODUCT_NAME: "PROD2", PRODUCT_QUANTITY_MT: "1002" }, { DATE: "2020-02-01", PRODUCT_NAME: "PROD3", PRODUCT_QUANTITY_MT: "45" }, { DATE: "2020-02-02", PRODUCT_NAME: "PROD1", PRODUCT_QUANTITY_MT: "20" }, { DATE: "2020-02-03", PRODUCT_NAME: "PROD1", PRODUCT_QUANTITY_MT: "10" }, { DATE: "2020-02-03", PRODUCT_NAME: "PROD2", PRODUCT_QUANTITY_MT: "230" }],
    final = [{ title: "DATE" }, { title: "PROD1" }, { title: "PROD2" }, { title: "PROD3" }],
    cols = final.reduce((r, { title }, i) => (r[title] = i, r), {}),
    result = data.reduce((r, { DATE, PRODUCT_NAME, PRODUCT_QUANTITY_MT }) => {
        var row = r.find(q => q[0] === DATE);
        if (!row) r.push(row = Array.from({ length: final.length }, (_, i) => i ? '' : DATE));
        row[cols[PRODUCT_NAME]] = PRODUCT_QUANTITY_MT;
        return r;
    }, []);

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

Answer:

We can use reduce method:

let final = my_json.reduce((a, {DATE, PRODUCT_NAME, PRODUCT_QUANTITY_MT}) => {
  a['DATE'] = a['DATE'] || {title: 'DATE'};
  a[PRODUCT_NAME] = a[PRODUCT_NAME] || {title: PRODUCT_NAME};
  return a;
},{})

let prepareData = my_json.reduce((a, c) => {
  a[c.DATE] = a[c.DATE] || {date: c.DATE, values:[]};
  if (c.PRODUCT_QUANTITY_MT) {
    a[c.DATE].values.push(c.PRODUCT_QUANTITY_MT);
  }
  return a;
},{})

let maxArrayLength = 0;
const data = Object.entries(prepareData).reduce((a, [k, v], i)=> {
  if (maxArrayLength < v.values.length) {
      maxArrayLength = v.values.length;
  } else {
    let fillByQuotes = Array.from({ length: maxArrayLength - v.values.length }, (i) => '');
    v.values.push(...fillByQuotes);
  }

  a.push([k, ...v.values]);
  return a;
}, []);

An example:

let my_json = [{
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "845",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "1002",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD3",
  PRODUCT_QUANTITY_MT: "45",
}, {
  DATE: "2020-02-02",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "20",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "10",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "230",
}]


let final = my_json.reduce((a, {DATE, PRODUCT_NAME, PRODUCT_QUANTITY_MT}) => {
  a['DATE'] = a['DATE'] || {title: 'DATE'};
  a[PRODUCT_NAME] = a[PRODUCT_NAME] || {title: PRODUCT_NAME};
  return a;
},{})

let prepareData = my_json.reduce((a, c) => {
  a[c.DATE] = a[c.DATE] || {date: c.DATE, values:[]};
  if (c.PRODUCT_QUANTITY_MT) {
    a[c.DATE].values.push(c.PRODUCT_QUANTITY_MT);
  }
  return a;
},{})

let maxArrayLength = 0;
const data = Object.entries(prepareData).reduce((a, [k, v], i)=> {
  if (maxArrayLength < v.values.length) {
      maxArrayLength = v.values.length;
  } else {
    let fillByQuotes = Array.from({ length: maxArrayLength - v.values.length }, (i) => '');
    v.values.push(...fillByQuotes);
  }

  a.push([k, ...v.values]);
  return a;
}, []);

console.log(Object.values(final));
console.log(data);

Answer:

Please check below code


function getDates (json) {
  var dates = [];

  json.forEach(ele => {
    if (!dates.includes(ele.DATE)) {
        dates.push(ele.DATE);
      }
  })

  return dates;
}


function getProducts (json) {
  let products = [];

  json.forEach(ele => {
    if (!products.includes(ele.PRODUCT_NAME)) {
        products.push(ele.PRODUCT_NAME);
      }
  })

  return products;
}

function getColumns (json) {
  let columns = [{ "title":"DATE" }];
  let dates = getDates(json);

  dates.forEach(date => {
    let column = { "title": date };
    columns.push(column);
  });

  return columns;
}

function getQuantityForDate(json, date) {
  let products = getProducts(json);
  let row = new Array(products.length + 1).fill("");
  row[0] = date;

  // Filter full data for a date
  let data = json.filter(ele => ele.DATE === date);

  // Filter product on particular date
  data.forEach(ele => {
    let product_index = products.indexOf(ele.PRODUCT_NAME);
    row[product_index + 1] = ele.PRODUCT_QUANTITY_MT;
  });

  return row;
}

function getFormattedData(json) {
    let grid_data = [];
    let dates = getDates(json);

    dates.forEach(date => {
      grid_data.push(getQuantityForDate(json, date));
    })

    return {
      "columns": getColumns(json),
      "data": grid_data
    }
}


let my_json = [{
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "845",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "1002",
}, {
  DATE: "2020-02-01",
  PRODUCT_NAME: "PROD3",
  PRODUCT_QUANTITY_MT: "45",
}, {
  DATE: "2020-02-02",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "20",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD1",
  PRODUCT_QUANTITY_MT: "10",
}, {
  DATE: "2020-02-03",
  PRODUCT_NAME: "PROD2",
  PRODUCT_QUANTITY_MT: "230",
}];

let grid_data = getFormattedData(my_json);
console.log(grid_data.columns)
console.log(grid_data.data)