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