I have an object with some nested data that I need to process programmatically to achieve a certain output. It will be the easiest to explain by demonstrating with example.
Example
I conducted an experiment and measured speed of dogs and cats running. I gathered the data in the following groups
object. We can see two major categories for each group, i.e., dogs
and cats
. Then, in each group, we have one property about the mean average speed time of the group members, as well as individuals
object that holds the data about each group member.
const groups = {
dogs: {
groupMeanRecord: 11.7,
individuals: {
lassie: {
record: 10,
age: 2,
},
slinky: {
record: 13,
age: 4,
},
toto: {
record: 11.5,
age: 1,
},
marley: {
record: 15,
age: 1,
},
beethoven: {
record: 9,
age: 13,
},
},
},
cats: {
groupMeanRecord: 7.75,
individuals: {
grumpyCat: {
record: 6,
age: 4,
},
salem: {
record: 9,
age: 11,
},
garfield: {
record: 5,
age: 3,
},
kitty: {
record: 11,
age: 10,
},
},
},
};
I want to figure out who are the animals, in each group, whose record
values are the lowest. I decided that I want the 3 lowest in each group. Hence, my desired output, given this current data, is:
const desiredOutput = {
dogs: 'beethoven, lassie, toto',
cats: 'garfield, grumpyCat, salem',
};
my attempt
Below is the code that I was able to come up with and it does give the desired output. However, as I'm new to JavaScript, I believe that there has to be an easier/more straightforward way to do this.
step 1 – clean up the data to get just what I need
const cleanDataArrOfArrs = Object.entries(groups).map( ([group, groupData]) => [ group, Object.entries(groupData.individuals).map(([individual, data]) => [ individual, data.record, ]), ] ); // [ // 'dogs', // [ // ['lassie', 10], // ['slinky', 13], // ['toto', 11.5], // ['marley', 15], // ['beethoven', 9], // ], // ], // [ // 'cats', // [ // ['grumpyCat', 6], // ['salem', 9], // ['garfield', 5], // ['kitty', 11], // ], // ], // ]
step 2 – I want to make the result of step 1 an object of objects
utilizing this helper function from here
const makeObject = (arr) => { return Object.fromEntries( arr.map(([key, val]) => Array.isArray(val) ? [key, makeObject(val)] : [key, val] ) ); };
calling
makeObject()
oncleanDataArrOfArrs
const cleanDataObj = makeObject(cleanDataArrOfArrs) // { // dogs: { lassie: 10, slinky: 13, toto: 11.5, marley: 15, beethoven: 9 }, // cats: { grumpyCat: 6, salem: 9, garfield: 5, kitty: 11 }, // };
step 3 – now I want to sort
cleanDataObj.dogs
andcleanDataObj.cats
properties from lowest to largest (respectively).- utilizing a helper function from this answer:
const sortObj = (o) => Object.fromEntries(Object.entries(o).sort((a, b) => a[1] - b[1]));
- and finally:
const myOutput = Object.fromEntries( Object.entries(cleanDataObj).map(([k, v]) => [ k, Object.keys(sortObj(v)).slice(0, 3).join(', '), ]) ); // { // dogs: 'beethoven, lassie, toto', // cats: 'garfield, grumpyCat, salem', // };
My worry is that this code, although working, is neither readable nor addressing the task properly, and that there might be a much simpler way to approach this. I'd therefore be happy to learn how such a task could be otherwise done.