0
\$\begingroup\$

I am formatting a data result from the array of objects that looks like this:

const data = {
  periods: [{
    month: 'January',
    sickLeave: {
        differance: '-12000',
        revision: '6000',
        paid: '18000',
    },
    holidayLeave: {
        differance: '10000',
        revision: '22000',
        paid: '12000',
    },
    received: '-2000',
    taken: '2000',
    result: '0',
  },
  {
    month: 'Februar',
    sickLeave: {
        differance: '-8000',
        revision: '6000',
        paid: '18000',
    },
    holidayLeave: {
        differance: '10000',
        revision: '22000',
        paid: '12000',
    },
    received: '-2000',
    taken: '2000',
    result: '0',
  }],
};

What I want to do with this is to make a new array that looks like this:

[{
  name: "sickLeaveDifferance",
  result:  ["-12000", "-8000"]
},
{
  name: "sickLeaveRevision",
  result: ["6000", "6000"]
},
{
  name: "sickLeavePaid",
  result: ["18000", "18000"]
},
{
  name: "holidayLeaveDifferance",
  result: ["10000", "10000"]
},
{
  name: "holidayLeaveRevision",
  result: ["22000", "22000"]
},
{  
  name: "holidayLeavePaid",
  result: ["12000", "12000"]
},
{
  name: "received",
  result: ["-2000", "-2000"]
},
{ 
  name: "taken",
  result: ["2000", "2000"]
},
{
  name: "result",
  result: ["0", "0"]
}]

I am achieving this with this function:

const formattedResult = perioder => {
  let resultArray = [];
  const pushNewValue = (key, value) => {
    const objectExists = resultArray.find(e => e.name === key);
    if (objectExists) {
      objectExists.result.push(value)
    } else {
      resultArray.push({
        name: key,
        result: [value]
      })
    }
  };

  perioder.map(el => 
   Object.entries(el).forEach(([key, value]) => {
     if (key != 'month') {
       if (key === 'sickLeave' || key === 'holidayLeave') {
         const prop = key;
         Object.entries(value).forEach(([key, value]) => {
           const name = `${prop + key[0].toUpperCase() + key.slice(1)}`;
           pushNewValue(name, value);
         })
       } else {
         pushNewValue(key, value);
       }
     }
   }))

   return resultArray;
}

But, I feel like there is a better, more elegant way of achieving this, just not sure how to do this?

Here is the fiddle.

\$\endgroup\$
1
\$\begingroup\$

Do you really anticipate the data model changing so much that this needs to be ultra flexible? In order to do so the code is quite complex - for instance having a forEach inside of an if inside of a forEach inside of a map. You already have model specific checks in the code anyways, such as the check for the 'sickLeave' and 'holidayLeave' keys. I think a solution along these lines would be perfectly acceptable:

const initialNormalizedVals = {
  "sickLeaveDifferance": [],
  "sickLeaveRevision": [],
  "sickLeavePaid": [],
  "holidayLeaveDifferance": [],
  "holidayLeaveRevision": [],
  "holidayLeavePaid": [],
  "received": [],
  "taken": [],
  "result": [],
}

const normalizedData = data.periods.reduce((outcome, { sickLeave, holidayLeave, received, taken, result }) => {
  outcome.sickLeaveDifferance.push(sickLeave.differance)
  outcome.sickLeaveRevision.push(sickLeave.revision)
  outcome.sickLeavePaid.push(sickLeave.paid)
  outcome.holidayLeaveDifferance.push(holidayLeave.differance)
  outcome.holidayLeaveRevision.push(holidayLeave.revision)
  outcome.holidayLeavePaid.push(holidayLeave.paid)
  outcome.result.push(result)
  outcome.taken.push(taken)
  outcome.received.push(received)

  return outcome
}, initialNormalizedVals)

const transformedData = Object.keys(normalizedData).map(key => {
  return {
    name: key,
    result: normalizedData[key],
  }
})

\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review! Your answer looks good, enjoy your stay! \$\endgroup\$ – ferada Oct 23 '18 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.