2

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:

enter image description here

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 ]

stone rock
  • 1,923
  • 9
  • 43
  • 72

5 Answers5

2

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.

charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Since `a[season]` does not exist (ie is `undefined`) adding a value to `undefined` equals `NaN`. try `isNaN(undefined+15)` – Bee157 Jun 20 '18 at 11:18
  • @Bee157 don't think you understand this answer. `(a[season] || 0 )` returns zero when `a[season]` is undefined – charlietfl Jun 20 '18 at 11:19
  • @charlietfl You answer works but I have 1 question: For particular season I want to sum all the `economy rate` an divide it by number of matches for that particular season. eg: season 2018 has 10,20,30,40 economy rate then the object which is returned by `reduce()` should be key value pairs of year and average economy rate. – stone rock Jun 20 '18 at 11:22
  • @charlietfl you're correct, it was actually a comment on the question and not on your answer, which is correct. – Bee157 Jun 20 '18 at 11:25
  • This answer solve just one part of the OP and is not complete. It fixes the sum but not the average part. Actually the average calculation is out of the code example provided from the OP. – Mario Santini Jun 20 '18 at 11:44
2

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Your answer works but I have 1 question: For particular season I want to sum all the economy rate an divide it by number of matches for that particular season. eg: season 2018 has 10,20,30,40 economy rate then the object which is returned by reduce() should be key value pairs of year and average economy rate – stone rock Jun 20 '18 at 11:24
  • do you have an example of the wanted output? – Nina Scholz Jun 20 '18 at 11:26
  • Wait I will add that in question – stone rock Jun 20 '18 at 11:26
  • I want to ask from where does `sum` and `count` come from ? Are you declaring it inside the `object : a` – stone rock Jun 20 '18 at 11:34
  • 1
    @stonerock, it is this line `a[season] = a[season] || { sum: 0, count: 0 };`, which check if the season exist (returns a truthy value) and if not, it assign an obejct with two properties. – Nina Scholz Jun 20 '18 at 11:37
  • If my initial value is `{}` instead of `Object.create(null)` then this line -> `a[season] = a[season] || { sum: 0, count: 0 };` will changed to this -> `a[season] = (a[season] || 0 { sum: 0, count: 0 });` is it correct ? – stone rock Jun 20 '18 at 11:43
  • no, you could keep it, no parenthesis required. `Object.create(null)` reated just a really empty object without prototypes. – Nina Scholz Jun 20 '18 at 11:44
  • Ok got it. Thanks for editing your answer again it is very helpful :) – stone rock Jun 20 '18 at 11:46
  • Is this line -> `a[season].sum += +econ;` calculating sum as well as incrementing econ by using this -> `+econ` am I correct ? – stone rock Jun 20 '18 at 11:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/173470/discussion-between-stone-rock-and-nina-scholz). – stone rock Jun 20 '18 at 11:49
1

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; 
}, {});
Sergio Mazzoleni
  • 1,458
  • 15
  • 24
  • Your answer works but I have 1 question: For particular season I want to sum all the economy rate an divide it by number of matches for that particular season. eg: season 2018 has 10,20,30,40 economy rate then the object which is returned by reduce() should be key value pairs of year and average economy rate – stone rock Jun 20 '18 at 11:23
1

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;

});
Lionel Rowe
  • 5,164
  • 1
  • 14
  • 27
1
     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))