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?

asked Apr 6, 2022 at 13:46
\$\endgroup\$

2 Answers 2

1
\$\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.

answered Apr 7, 2022 at 14:09
\$\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\$ 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]))
answered Apr 9, 2022 at 2:00
\$\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\$ Commented Apr 12, 2022 at 14:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.