• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
    • Questions
    • Teachers
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

218
Views
JS - How to transform an array of objects into different groups based off property value, further segregate data, and aggregating some of the data

Let' say I have an array of objects like this:

[
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2016",
    "transactiondate": "2016-02-01T08:00:00Z",
    "level": "level 1",
    "amount": "5"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2017",
    "transactiondate": "2017-02-01T08:00:00Z",
    "level": "level 1",
    "amount": "7"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2017",
    "transactiondate": "2017-02-01T08:00:00Z",
    "level": "level 1",
    "amount": "4"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2016",
    "transactiondate": "2016-02-01T08:00:00Z",
    "level": "level 2",
    "amount": "10"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2016",
    "transactiondate": "2016-02-01T08:00:00Z",
    "level": "level 2",
    "amount": "20"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2017",
    "transactiondate": "2017-02-01T08:00:00Z",
    "level": "level 2",
    "amount": "50"
    },
    ...
]

I want the output to look like this:

[
    {
        name: "level 1",
        data: [5, 11] // Total amount in order of ascending year. 2016 had total amount of 5 and 2017 had total amount of 11
    },
    {
        name: "level 2",
        data: [30, 50]
    },
    {
        name: "level x",
        data: [...]
    }
]

I was able to successfully group it by year by doing the following but I'm not quite sure how to go about taking the resulting object then transforming it into the desired output. I would have to loop through entries of the object, split it up into groups by "level", iterate through the entries again then use reduces to accumulate the amounts, then split them up again into "name" and "data" key/value pairs? I feel like that is very inefficient if I can even get that to work. Any help would be much appreciated.

var groupedByYr = data.reduce(function (r, a) {
                r[a.transactiondate.substring(0,4)] = r[a.transactiondate.substring(0,4)] || [];
                r[a.transactiondate.substring(0,4)].push(a);
                return r;
            });
almost 3 years ago · Juan Pablo Isaza
2 answers
Answer question

0

maybe not the perfect answer but it has a 1 loop I guess :D

I tried to explain it in the code as much as I could

var data = [{
      "transactiondate.Display.V1.FormattedValue": "2/1/2016",
      "transactiondate": "2016-02-01T08:00:00Z",
      "level": "level 1",
      "amount": "5"
    },
    {
      "transactiondate.Display.V1.FormattedValue": "2/1/2017",
      "transactiondate": "2017-02-01T08:00:00Z",
      "level": "level 1",
      "amount": "7"
    },
    {
      "transactiondate.Display.V1.FormattedValue": "2/1/2017",
      "transactiondate": "2017-02-01T08:00:00Z",
      "level": "level 1",
      "amount": "4"
    },
    {
      "transactiondate.Display.V1.FormattedValue": "2/1/2016",
      "transactiondate": "2016-02-01T08:00:00Z",
      "level": "level 2",
      "amount": "10"
    },
    {
      "transactiondate.Display.V1.FormattedValue": "2/1/2016",
      "transactiondate": "2016-02-01T08:00:00Z",
      "level": "level 2",
      "amount": "20"
    },
    {
      "transactiondate.Display.V1.FormattedValue": "2/1/2017",
      "transactiondate": "2017-02-01T08:00:00Z",
      "level": "level 2",
      "amount": "50"
    },
  ],
  parse = [] //save parse array,
  levels = {} //save level keys;
data.map((item) => {
  let map = new Map(); // create a map for location of the value of the each year
  if (typeof levels[item.level] == 'undefined') { // we didn't parse the level yet so it's new
    map.set(item.transactiondate.substring(0, 4), 0); // set the location of the amount of the first year as 0 because it's the first
    let key = parse.push({
      name: item.level,
      yearindexes: map,
      data: [parseInt(item.amount)]
    }); // save the parse array size as level key
    levels[item.level] = key - 1;  // save the level and index of it (key -1) 
  } else {
   // parse the level before so it's exists
    if (parse[levels[item.level]].yearindexes.has(item.transactiondate.substring(0, 4))) { // we have the year in the data
    let yearindex = parse[levels[item.level]].yearindexes.get(item.transactiondate.substring(0, 4)); // get the index of the year
      parse[levels[item.level]].data[yearindex] += parseInt(item.amount); // add the amount of the year to the index
    } else {
      // it's a new years
      parse[levels[item.level]].data.push(parseInt(item.amount));// push the new year amount to the data
      map = parse[levels[item.level]].yearindexes; // get previes year indexes
      map.set(item.transactiondate.substring(0, 4), map.size); // add the new year with the size of yearindexes as the index of the new year
      parse[levels[item.level]].yearindexes = map; // set the new yearindexes
    }
  }
});
//remove yearindexes from parse (optional)
const result = parse.map(({yearindexes,...rest}) => ({...rest}));
console.log(result);

almost 3 years ago · Juan Pablo Isaza Report

0

I think you're just going to have to do it in two passes, one with forEach to get everything into a buffer, and one with map to take that buffer and format it how you like. I think you can do it in one pass, but it is going to be a lot easier to read if you don't.

Here I use forEach to loop over the data elements, and I use an object buffer. Since it's an object, I can use keys to keep the entries unique, and keep adding the amounts for each year using the year as a subkey (which I get from Date's getYear()). The first time you hit each key, you will either need to check for its existence in the target object OR you can do what I did, null coalesce to a default value (either an empty object or 0).

Then when the buffer is built, I use Object.values to map the object to an array and also to convert the amounts objects to arrays.

Let me know if I got that right.

const data = [
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2016",
    "transactiondate": "2016-02-01T08:00:00Z",
    "level": "level 1",
    "amount": "5"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2017",
    "transactiondate": "2017-02-01T08:00:00Z",
    "level": "level 1",
    "amount": "7"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2017",
    "transactiondate": "2017-02-01T08:00:00Z",
    "level": "level 1",
    "amount": "4"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2016",
    "transactiondate": "2016-02-01T08:00:00Z",
    "level": "level 2",
    "amount": "10"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2016",
    "transactiondate": "2016-02-01T08:00:00Z",
    "level": "level 2",
    "amount": "20"
    },
    {
    "transactiondate.Display.V1.FormattedValue": "2/1/2017",
    "transactiondate": "2017-02-01T08:00:00Z",
    "level": "level 2",
    "amount": "50"
    }
];


let buffer = {};
data.forEach(i=>{
  let t = new Date(i.transactiondate).getYear();
  let amts = buffer[i.level]?.amts || {};
  amts[t] = i.amount*1 + (amts[t] || 0);
  buffer[i.level] = {name: i.level, amts: amts};
});

//console.log(buffer);
let final = Object.values(buffer).map(m=>{
  return {name: m.name, data: Object.values(m.amts)};
});

console.log(final);

almost 3 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error