Reputation: 1953
I am trying to extract econ
and season
from JSON data (see screenshot below). I want to find average economy rate per season
eg: season = 2018 economy rate = 10,20,30 so avg economy rate = (10+20+30)/3 = 20
season = 2017 economy rate = 30,40,50 so avg economy rate = (30+40+50)/3 = 40
So I want to calculate sum of all the economy rate for particular season and then take the average i.e divide the total sum for particular season by number of matches in that season.
Below is the code where I am trying to make use of reduce()
in ES6:
const economy = bowldata.reduce( (a,{season, econ}) => {
a[season] = a[season] + parseInt(econ);
return a;
}, {});
console.log(economy);
I am getting 2018:NaN
but instead I want my output to be 2018:22 , 2017: 50, etc. i.e I want key value pairs of season and average economy rate for that season.
Screenshot:
Let's say I have JSON data:
var bowldata = [
{
season:2018
economy:10
},
{ season:2018
economy:20
},
{ season:2018
economy:30
},
{ season:2017
economy:40
},
{ season:2017
economy:50
},
{ season:2016
economy:10
},
]
Now the object which reduce()
should return is key value pairs of year and average economy rate.
Result: [ 2018:20 , 2017:45 , 2016:10 ]
Upvotes: 2
Views: 1412
Reputation: 45
Hi you can solve the problem by following chain of reduce and map: i) Reduce to season and economies aggregation ii) Map to get season and avg economy iii)Map to get the season and economy key value string
bowldata.reduce((acc,b)=>{
const y =acc.find(x => x.s ===b.s);
y? y.e.push(b.e) :acc.push({s:b.s, e:[b.e]});
return acc
},[])
.map(x => ({s:x.s,e:x.e.reduce((acc,b,i)=> (acc*i + parseInt(b))/(i+1),0)})
)
.map( x=> (x.s +':' + x.e))
Upvotes: 1
Reputation: 386746
You could take an object as default value for any seasons, becaus you want to calculate the average. For this, you need the count as well.
var bowldata = [{ season: 2001, econ: '30' }, { season: 2001, econ: '40' }, { season: 2001, econ: '50' }, { season: 2001, econ: '60' }, { season: 2002, econ: '30' }, { season: 2002, econ: '40' }, { season: 2002, econ: '50' }, { season: 2003, econ: '60' }, { season: 2003, econ: '30' }, { season: 2003, econ: '40' }, { season: 2003, econ: '50' }, { season: 2003, econ: '60' }],
economy = bowldata.reduce((a, { season, econ }) => {
a[season] = a[season] || { sum: 0, count: 0 };
a[season].sum += +econ;
a[season].average = a[season].sum / ++a[season].count;
return a;
}, Object.create(null)),
nice = Object.assign(...Object
.entries(economy)
.map(([k, { average }]) => ({ [k]: average }))
);
console.log(nice);
console.log(economy);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 2
Reputation: 5926
To calculate averages rather than totals, you're probably best served with a two-step process, something like this:
const totals = bowldata.reduce((acc, cur) => {
if (!acc[cur.season]) {
acc[cur.season] = {count: 0, total: 0};
}
acc[cur.season].count++;
acc[cur.season].total += parseInt(cur.econ);
return acc;
}, {});
const averages = {};
Object.keys(totals).forEach(key => {
averages[key] = totals[key].total / totals[key].count;
});
Upvotes: 1
Reputation: 1608
the first time you execute a[season] = a[season] + parseInt(econ);
, a[season]
is not defined. Just initialize it with 0
the fist time you access it.
const economy = bowldata.reduce( (a,{season, econ}) => {
if (!a[season]) {
a[season] = 0;
}
a[season] = a[season] + parseInt(econ);
return a;
}, {});
Upvotes: 1
Reputation: 171690
Change
a[season] = a[season] + parseInt(econ);
To
a[season] = (a[season] || 0 ) + parseInt(econ);
This will account for first instance not having set that property yet so when it is undefined you will be adding the new value to zero.
Upvotes: 2