K Y
K Y

Reputation: 211

Javascript manipulate data into array of object for d3 stacked chart

I have:

[{ID: "1", Job: "Student", Gender: "Male", Income: 2200}, 
{ID: "2", Job: "Student", Gender: "Male", Income: 1300},
{ID: "3", Job: "Student", Gender: "Female", Income: 5400},
{ID: "4", Job: "Teacher", Gender: "Female", Income: 4200},
{ID: "5", Job: "Teacher", Gender: "Female", Income: 4000}]

Trying to manipulate into the below format for d3 stacked bar chart (like the data in this link) :

[{name: "Student", Male: 3500, Female: 5400},
{name: "Teacher", Male: 0, Female: 8200}]

I tried all sorts of for-loop and sums and got myself all confused, so I won't bore you with my lengthy inefficient code. How would you do it?

Upvotes: 3

Views: 83

Answers (2)

Ben Stephens
Ben Stephens

Reputation: 3371

I would probably do it like this for my own code. One concern might be that the get_totals_by_job function is a bit difficult to understand without some effort.

const data = [{ID: "1", Job: "Student", Gender: "Male", Income: 2200}, 
{ID: "2", Job: "Student", Gender: "Male", Income: 1300},
{ID: "3", Job: "Student", Gender: "Female", Income: 5400},
{ID: "4", Job: "Teacher", Gender: "Female", Income: 4200},
{ID: "5", Job: "Teacher", Gender: "Female", Income: 4000}];

const get_totals_by_job = (acc, val) => Object.assign(
  acc,
  {
    [val.Job]: Object.assign(
      acc[val.Job] || { Male: 0, Female: 0 },
      { [val.Gender]: (acc[val.Job]?.[val.Gender] || 0) + val.Income }
    )
  }
);

const result = Object
  .entries( data.reduce(get_totals_by_job, {}) )
  .map( ([name, totals]) => Object.assign({ name }, totals) );

console.log(result);

Upvotes: 0

Ran Turner
Ran Turner

Reputation: 18036

You can use reduce for that.

The reduce method executes a reducer function on each element of the array. the reducer function's returned value is assigned to the accumulator (res). this value is remembered for each iteration throughout the array. the second value is the current value which we will use to figure out is this a Male/Female and add to the relatively gender income.

const data = [{ID: "1", Job: "Student", Gender: "Male", Income: 2200}, 
{ID: "2", Job: "Student", Gender: "Male", Income: 1300},
{ID: "3", Job: "Student", Gender: "Female", Income: 5400},
{ID: "4", Job: "Teacher", Gender: "Female", Income: 4200},
{ID: "5", Job: "Teacher", Gender: "Female", Income: 4000}];

var result = [];
data.reduce(function(res, value) {
  if (!res[value.Job]) {
    res[value.Job] = { name: value.Job, Male: 0, Female: 0 };
    result.push(res[value.Job])
  }
  if (value.Gender === "Male"){
    res[value.Job].Male += value.Income;
  }
  else{
    res[value.Job].Female += value.Income;
  }
  return res;
}, {});

console.log(result)

Upvotes: 2

Related Questions