I'm not sure if there is an easy solution to this problem, but I want to sort an array of objects, that have a nested array of objects, based on this array of objects y value and the parent x key. The difficult part is that both of the arrays get combined together to represent some data.
Here is the data structure
series: [
{
name: 'testData',
data: [
{x: abc, y: 488},
{x: def, y: 65},
{x: ghi, y: 380},
{x: jkl, y: 190}
]
},
{
name: 'testData2',
data: [
{x: abc, y: 241},
{x: def, y: 232},
{x: ghi, y: 72},
{x: jkl, y: 724}
]
}
]
At this stage, there is only the two parent objects, so I need to compare each object and reorder them, the end result would look like
[
{
name: 'testData',
data: [
{x: jkl, y: 190}, // total for key jkl y combined values is 914
{x: abc, y: 488}, // total for key abc y combined values is 729
{x: ghi, y: 380}, // total for key ghi y combined values is 452
{x: def, y: 65}, // total for key def y combined values is 297
]
},
{
name: 'testData2',
data: [
{x: jkl, y: 724}, // total for key jkl y combined values is 914
{x: abc, y: 241}, // total for key abc y combined values is 729
{x: ghi, y: 72}, // total for key ghi y combined values is 452
{x: def, y: 232} // total for key def y combined values is 297
]
}
]
I've tried a couple of ideas but can't seem to find a solution to my problem if you've seen a nice solution elsewhere please feel free to link it.
Here is something I tried
series.forEach(obj => {
obj.data.sort((a, b) => {
return b.y - a.y;
});
});
But it just ends up moving the highest values in each array to the top, not the one which should match the other array. It's hard to give context but I'm using Apexcharts which uses the data to make a graph like this:
| testData | testData2
---------------------------
abc ------ GraphBar ------
def ------ AnotherBar ----
ghi ------ thirdBar ------
jkl ------ fourthBar -----
---------------------------
So I need to figure out how to sort based on the bar's cumulative values, based on both the two objects data array y values.
This is what it looks like presorting
And after, as you can see its modifying the data
Assuming that we name the variable series
as in
const series = [
{
name: 'testData',
data: [
{ x: 'abc', y: 488 },
{ x: 'def', y: 65 },
{ x: 'ghi', y: 380 },
{ x: 'jkl', y: 190 }
]
},
{
name: 'testData2',
data: [
{ x: 'abc', y: 241 },
{ x: 'def', y: 232 },
{ x: 'ghi', y: 72 },
{ x: 'jkl', y: 724 }
]
}
]
(note that I've made the x
properties have string
values instead of bare identifiers like abc
; I assume that's what you want)
We can possibly tackle your sorting task like this. First, let's get an object whose keys are the x
values and whose values are the sums of the y
values:
const sums = series.reduce(
(s, r) => (r.data.forEach(xy => s[xy.x] = (s[xy.x] || 0) + xy.y), s),
{} as Record<string, number>
);
console.log(sums); // { abc: 729, def: 297, ghi: 452, jkl: 914 }
Note that I'm using the comma operator inside the reduce
where the first part does the mutation and the last part hands back the object to be mutated. It's not necessarily any better than using a for
loop, other than being terse.
Now we can sort the data
in series
by using sums
:
series.forEach(v => v.data.sort((a, b) => sums[b.x] - sums[a.x]));
console.log(JSON.stringify(series,null,2));
/*
[
{
"name": "testData",
"data": [
{
"x": "jkl",
"y": 190
},
{
"x": "abc",
"y": 488
},
{
"x": "ghi",
"y": 380
},
{
"x": "def",
"y": 65
}
]
},
{
"name": "testData2",
"data": [
{
"x": "jkl",
"y": 724
},
{
"x": "abc",
"y": 241
},
{
"x": "ghi",
"y": 72
},
{
"x": "def",
"y": 232
}
]
}
]
*/
Looks reasonable to me. Okay, hope that helps; good luck!