Home > Mobile >  Restructuring Javascript Array of Objects
Restructuring Javascript Array of Objects

Time:04-21

I have a set of data which I'm trying to convert it into a different structure. I have almost reached the requirement but I'm stuck at the last part. Here's the code and what I have tried so far.

let array1 = [
  {
    aggr_type: "mean",
    date: ['19 Apr', '20 Apr'],
    mean: [13.87, 8.42],
    name: "TEMPERATURE",
    sum: [0.1, 0.2]
  },
  {
    aggr_type: "sum",
    date: ['19 Apr', '20 Apr'],
    mean: [45.42, 55.22],
    name: "HUMIDITY",
    sum: [0.3, 0.5]
  }
];
let names = [];
array1.forEach(el => {
  names.push(el.name);
});
const myObj = names.reduce((a, key) => Object.assign(a, { [key]: null, date: null }), {});
// console.log(myObj);
// console.log(array1);
let arrays = []

for(i=0; i < array1[0].date.length; i  ) {
  array1.forEach(el => {
    myObj.date = el.date[i];
    myObj[el.name] = el.[el.aggr_type][i];
    arrays.push(myObj);
  });
}

console.log(arrays);

If this snippet isn't working use this codepen

I'm supposed to have the output like this.

    [
{
  'TEMPERATURE': '13.87',
 'date': '19 Apr',
 'HUMIDITY': '0.3'
},
{
  'TEMPERATURE': '8.42', 
  'date': '20 Apr', 
  'HUMIDITY': '0.5'
}
];

But it only returns the last index. Is there any way to get the output like I've mentioned above.

NOTE: The values should be added the final output based on the aggr_type

CodePudding user response:

The below may be one possible solution to achieve the desired objective.

Code Snipppet

// method to obtain the desired objective
const groupByDate = arr => (
  Object.values(        // extract only the "values" from result of "reduce"
    arr.reduce(         // use "reduce" to iterate over the array
      (acc, {name, date, mean}) => {
        date.forEach(   // for each "date" in the "date-array"
          (d, i) => {   // populate / update the "acc" (accumulator)
            acc[d] = {
              ...(acc[d] || {}),
              [name]: mean[i],    // this line populates either temperator or humidity
              date: d,
            }
          }
        )
        return acc;       // always return the "acc" 
      },
      {}                  // initially the "acc" is set as an empty object
    )
  )
);

let array1 = [
  {
    aggr_type: "mean",
    date: ['19 Apr', '20 Apr'],
    mean: [13.87, 8.42],
    name: "TEMPERATURE",
    sum: [0.1, 0.2]
  },
  {
    aggr_type: "sum",
    date: ['19 Apr', '20 Apr'],
    mean: [45.42, 55.22],
    name: "HUMIDITY",
    sum: [0.3, 0.5]
  }
];

console.log(groupByDate(array1));

Explanation Inline comments in the above snippet explain the significant aspects.

EDIT

Used the input array array1 that was updated on the question. The answer from the snippet matches with the expected array on the question:

[
{
  'TEMPERATURE': '13.87',
 'date': '19 Apr',
 'HUMIDITY': '45.42'
},
{
  'TEMPERATURE': '8.42', 
  'date': '20 Apr', 
  'HUMIDITY': '55.22'
}
];

EDIT 2

// method to obtain the desired objective
const groupByDate = arr => (
  Object.values(        // extract only the "values" from result of "reduce"
    arr.reduce(         // use "reduce" to iterate over the array
      (acc, ob) => {
        const {name, date, aggr_type} = ob;
        const tgt = ob[aggr_type];    // decide whether to use "mean" or "sum"
        date.forEach(   // for each "date" in the "date-array"
          (d, i) => {   // populate / update the "acc" (accumulator)
            acc[d] = {
              ...(acc[d] || {}),
              [name]: tgt[i],    // this line populates either temperature or humidity
              date: d,
            }
          }
        )
        return acc;       // always return the "acc" 
      },
      {}                  // initially the "acc" is set as an empty object
    )
  )
);

let array1 = [
  {
    aggr_type: "mean",
    date: ['19 Apr', '20 Apr'],
    mean: [13.87, 8.42],
    name: "TEMPERATURE",
    sum: [0.1, 0.2]
  },
  {
    aggr_type: "sum",
    date: ['19 Apr', '20 Apr'],
    mean: [45.42, 55.22],
    name: "HUMIDITY",
    sum: [0.3, 0.5]
  }
];

console.log(groupByDate(array1));

CodePudding user response:

The problem is that you have created a single myObj

const myObj = names.reduce((a, key) =>
                  Object.assign(a, { [key]: null, date: null }), {});

and you assign to it and then push it within your loop

for (i=0; i < array1[0].date.length; i  ) {
    array1.forEach(el => {
                       myObj.date = el.date[i];  // <-- modifies the ONE 'myObj'
                       myObj[el.name] = el.[el.aggr_type][i];
                       arrays.push(myObj); // <-- pushes the ONE myObj (again)
    });
}

You end up with 4 references to myObj in your arrays — each time you assign to it, for example myObj.date = el.date[i], you are modifying that one and only myObj ... That is, after the first time you do arrays.push(myObj) you have arrays[0] containing myObj, then the next time through the loop when you assign values to myObj again that is changing the values that are in arrays[0] since that is myObj.

You can treat myObj as a prototype — you need separate instances of objects that look like myObj so each one pushed into arrays is a unique object.

Modifying your original code as little as possible, here is one way that could be done:

let array1 = [
    {
        aggr_type: "mean",
        date: ['19 Apr', '20 Apr'],
        mean: [13.87, 8.42],
        name: "TEMPERATURE",
    },
    {
        aggr_type: "mean1",
        date: ['19 Apr', '20 Apr'],
        mean: [45.42, 55.22],
        name: "HUMIDITY",
    }
];
let names = [];
array1.forEach(el => {
    names.push(el.name);
});
// Changed the name here so I wouldn't have to change it in the loop
const protoMyObj = names.reduce((a, key) =>
    Object.assign(a, { [key]: null, date: null }), {});
// console.log(myObj);
// console.log(array1);
let arrays = []

for (i=0; i < array1[0].date.length; i  ) {
    array1.forEach(el => {
        // Make a new copy of the "prototype" `protoMyObj`
        let myObj = Object.assign({}, protoMyObj);
        myObj.date = el.date[i];
        myObj[el.name] = el.mean[i];
        arrays.push(myObj);
    });
}

console.log(arrays);

  • Related