1
\$\begingroup\$

I want to sum up and flatten the structure of an API response. Since I didn't succeed by iterating over the key/value pairs of input.statistic I came up with another solution which does the job but I'm not happy with it.

What I do recieve is:

input = {
"data": some unimportant stuff,
"statistic": [
    {
      "valueId": 111,
      "statistic": {
        "min": 0,
        "max": 0,
        "average": 0.12
      }
    },
    {
      "valueId": 222,
      "statistic": {
        "min": 0,
        "max": 1,
        "average": 0.14
      }
    }
  ]
}

At this point I'm only interested in the statistic data and I want to change it to something like that:

{
"stat111": [
   {name: "min", value: 0},
   {name: "max", value: 0},
   {name: "average", value: 0.12}
  ],
"stat222": [
   {name: "min", value: 0},
   {name: "max", value: 1},
   {name: "average", value: 0.14}
  ]
}

What I do is:

const statDat = {};
for (const item of input.statistic) {
  const nameTop = 'stat' + item.valueId.toString();
  const props = [];
    for (let key in item.statistic) {
      props.push({name: key, value: item.statistic[key]});
    }
  statDat[nameTop] = props;
}

So statDat looks the way I want it but once more I'm sure that there is a better and newer way of flatten and renaming the structure. Any hints?

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

If you're looking for "newer", then I would recommend familiarizing yourself with a good Javascript api, such as the Mozilla Developer Network's. That has such entries as array's forEach, Object.entries, destructuring assignments, and arrow functions. Those (and the new object notation) combine to change your code to

const statDat = {};
input.statistic.forEach( (item) => {
    const nameTop = 'stat' + item.valueId; // toString() unnecessary
    statDat[nameTop] = Object.entries(item.statistic).map( ([name,value]) => ({name,value}) );
});

we can also use Object.fromEntries as in Jonah's answer to get these five lines down to one command (which I break into 4 lines for readability).

const statDat2 = Object.fromEntries( input.statistic.map( ({valueId,statistic}) => [
    'stat'+valueId,
    Object.entries(statistic).map( ([name,value]) => ({name,value}) )
] ) );

const input = {
"data": "some unimportant stuff",
"statistic": [
    {
      "valueId": 111,
      "statistic": {
        "min": 0,
        "max": 0,
        "average": 0.12
      }
    },
    {
      "valueId": 222,
      "statistic": {
        "min": 0,
        "max": 1,
        "average": 0.14
      }
    }
  ]
};
const statDat = {};
input.statistic.forEach( (item) => {
    const nameTop = 'stat' + item.valueId;
    statDat[nameTop] = Object.entries(item.statistic).map( ([name,value]) => ({name,value}) );
});
console.log(statDat);
// or
const statDat2 = Object.fromEntries( input.statistic.map( ({valueId,statistic}) => [
    'stat'+valueId,
    Object.entries(statistic).map( ([name,value]) => ({name,value}) )
] ) );
console.log(statDat2);

Compressing five lines of code into one usually makes that one line a bit harder to understand than any of the five original lines, but much easier to understand overall.

\$\endgroup\$
2
  • \$\begingroup\$ I do agree with you that a one liner makes it harder to understand - although Jonahs answer works very well, too. Thxs! \$\endgroup\$ Commented Apr 12, 2022 at 8:52
  • \$\begingroup\$ TBH, I like the Object.fromEntries approach. \$\endgroup\$
    – Teepeemm
    Commented Apr 12, 2022 at 14:31
1
\$\begingroup\$

Essentially, your data transformation is just a map, and we want the code to reflect that. Here's a one liner with no mutation or intermediate variables:

Object.fromEntries(input.statistic.map(x => [`stat${x.valueId}`, x.statistic]))
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Thxs for your solution. It works very well, too. \$\endgroup\$ Commented Apr 12, 2022 at 8:53
  • \$\begingroup\$ (Although you need to work with x.statistic to match OP's output.) \$\endgroup\$
    – Teepeemm
    Commented Apr 12, 2022 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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