问题:
I have an array of objects that appears as follows:
var dataArray = [{ "moment": "18 January 2019", "val": 53 },
{ "moment": "18 January 2019", "val": 69...
可以将文章内容翻译成中文,广告屏蔽插件会导致该功能失效:
问题:
I have an array of objects that appears as follows:
var dataArray = [{ "moment": "18 January 2019", "val": 53 },
{ "moment": "18 January 2019", "val": 69 },
{ "moment": "18 January 2019", "val": 52 },
{"moment": "21 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 }]
What I would like to do is to put in a new array the value of the element moment and the average of val for that moment. eg:
result =[{moment: "18 January 2019", "val": 58},
{moment: "21 January 2019", "val": 52}].
For now I managed to put a single occurence of each date in the new array result but I am having hard time to put the average since I don't know how to make the difference between values for a date from values for another date. Any help would be appreciated.
Peace
回答1:
You can do it using reduce.
Here first we aggregate the values by moment and also count no. of similar moments. and than map through it and find the average using the aggregated value and count.
var dataArray = [{ "moment": "18 January 2019","val": 53 },{ "moment": "18 January 2019", "val": 69 },{ "moment": "18 January 2019", "val": 52 },{"moment": "21 January 2019", "val": 52 }, { "moment": "21 January 2019", "val": 52 }, { "moment": "21 January 2019", "val": 52 }]
let output = dataArray.reduce((op,cur)=>{
if( op[cur.moment] ){
op[cur.moment].val += cur.val;
op[cur.moment].count++;
} else {
op[cur.moment] = cur
op[cur.moment].count = 1;
}
return op;
},{})
let final = Object.values(output).map(e => {
return {
moment: e.moment,
val: e.val/e.count
}
})
console.log(final)
回答2:
var totalCount = 0;
var divBy = 0;
var momentToCheck = "21 January 2019"
for(int i= 0; i<dataArray.length; i++) {
if (dataArray[i].moment === momentToCheck) {
totalCount+= dataArray[i].val;
divBy++;
}
}
var newAvg = totalCount/divBy;
dataArray.push({moment:momentToCheck, val:newAvg});
回答3:
It might make sense to first perform a grouping, and then to perform the average of each group. For example:
const dataArray = [{ "moment": "18 January 2019", "val": 53 },
{ "moment": "18 January 2019", "val": 69 },
{ "moment": "18 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 }]
const groups = dataArray.reduce((r, { moment, val }) => {
(r[moment] = r[moment] || []).push(val)
return r
}, {})
const avg = arr => arr.reduce((r, x) => r + x, 0) / arr.length
const result = Object.entries(groups).map(([moment, arr]) => ({
moment,
avg: avg(arr)
}))
console.log(result)
回答4:
You can achieve the expected result in the following way using reduce
var dataArray = [{
"moment": "18 January 2019",
"val": 53
},
{
"moment": "18 January 2019",
"val": 69
},
{
"moment": "18 January 2019",
"val": 52
},
{
"moment": "21 January 2019",
"val": 52
},
{
"moment": "21 January 2019",
"val": 52
},
{
"moment": "21 January 2019",
"val": 52
}
];
const result = dataArray.reduce((accumulator, currentValue, index, array) => {
if (!accumulator[currentValue.moment]) {
accumulator[currentValue.moment] = array
.filter(arr => arr.moment === currentValue.moment)
.reduce((acc, val, idx, coll) => {
acc += val.val;
if (idx === coll.length - 1) {
return acc/coll.length;
} else {
return acc;
}
}, 0);
}
return accumulator;
}, []);
console.log(result); // [ '18 January 2019': 58, '21 January 2019': 52 ]
回答5:
Use array reduce and inside the call back check if the arument array have moment with same value
var dataArray = [{
"moment": "18 January 2019",
"val": 53
},
{
"moment": "18 January 2019",
"val": 69
},
{
"moment": "18 January 2019",
"val": 52
},
{
"moment": "21 January 2019",
"val": 52
},
{
"moment": "21 January 2019",
"val": 52
},
{
"moment": "21 January 2019",
"val": 52
}
]
let avgVal = dataArray.reduce(function(acc, curr) {
let findIfHasDate = acc.findIndex((item) => {
return item.moment === curr.moment
});
if (findIfHasDate === -1) {
acc.push({
moment: curr.moment,
totalVal: curr.val,
totalcount: 1
})
} else {
acc[findIfHasDate].totalVal = (acc[findIfHasDate].totalVal + curr.val);
acc[findIfHasDate].totalcount += 1;
}
return acc;
}, []).map((item) => {
return {
moment: item.moment,
avg: (item.totalVal) / item.totalcount
}
})
console.log(avgVal)
回答6:
const summarize = data => data.reduce(
(a, c) => (prev => (
{ ...a, [c.moment]: { sum: (prev.sum + c.val), count: (prev.count + 1) } }
))(a[c.moment] || { sum: 0, count: 0 }),
{}
)
const average = summary => Object.keys(summary).map(
k => ({ moment: k, val: (summary[k].sum / summary[k].count) })
)
console.log(average(summarize([
{ "moment": "18 January 2019", "val": 53 },
{ "moment": "18 January 2019", "val": 69 },
{ "moment": "18 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 },
{ "moment": "21 January 2019", "val": 52 }
])))