I have a multidimensional array that I'm trying to sort by the 3-letter month abbreviation, here's what I have tried:
The array:
$shipping_chart_month =
[
{
"name": "8:00 AM",
"data": [
{
"x": "May",
"y": 37
},
{
"x": "Nov",
"y": 32
},
{
"x": "Apr",
"y": 1
},
{
"x": "Aug",
"y": 45
},
{
"x": "Sep",
"y": 19
},
{
"x": "Jul",
"y": 13
},
{
"x": "Oct",
"y": 43
},
{
"x": "Jun",
"y": 31
},
{
"x": "Feb",
"y": 0
},
{
"x": "Jan",
"y": 0
},
{
"x": "Mar",
"y": 0
}
]
},
{
"name": "9:00 AM",
"data": [
{
"x": "Apr",
"y": 26
},
{
"x": "Oct",
"y": 84
},
{
"x": "Sep",
"y": 35
},
{
"x": "Jul",
"y": 26
},
{
"x": "Feb",
"y": 6
},
{
"x": "Nov",
"y": 96
},
{
"x": "Mar",
"y": 10
},
{
"x": "May",
"y": 50
},
{
"x": "Aug",
"y": 66
},
{
"x": "Jun",
"y": 36
},
{
"x": "Jan",
"y": 0
}
]
}
]
I'm trying to sort each sub data
array by Month. Here's what I've tried but it doesn't seem to have any affect and stuck on where to go from here:
foreach ($shipping_chart_month as $data) {
$months = [];
foreach ($data['data'] as $month) {
$months[] = $month['x'];
}
usort($months, function ($x, $y) {
$months = array('Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12);
if ($months[$x] == $months[$y]) {
return 0;
}
return ($months[$x] > $months[$y]) ? 1 : -1;
});
}
CodePudding user response:
Starting with your data in a JSON string, which is what you've presented above:
$shipping = '[
{
"name": "8:00 AM",
"data": [
{
"x": "May",
"y": 37
},
{
"x": "Nov",
"y": 32
},
{
"x": "Apr",
"y": 1
},
{
"x": "Aug",
"y": 45
},
{
"x": "Sep",
"y": 19
},
{
"x": "Jul",
"y": 13
},
{
"x": "Oct",
"y": 43
},
{
"x": "Jun",
"y": 31
},
{
"x": "Feb",
"y": 0
},
{
"x": "Jan",
"y": 0
},
{
"x": "Mar",
"y": 0
}
]
},
{
"name": "9:00 AM",
"data": [
{
"x": "Apr",
"y": 26
},
{
"x": "Oct",
"y": 84
},
{
"x": "Sep",
"y": 35
},
{
"x": "Jul",
"y": 26
},
{
"x": "Feb",
"y": 6
},
{
"x": "Nov",
"y": 96
},
{
"x": "Mar",
"y": 10
},
{
"x": "May",
"y": 50
},
{
"x": "Aug",
"y": 66
},
{
"x": "Jun",
"y": 36
},
{
"x": "Jan",
"y": 0
}
]
}
]';
// json_decode() the data so we can work with it.
$shipping_chart_month = json_decode($shipping);
// Loop through the array of objects, looking at the $data property in each one
foreach($shipping_chart_month as $chart) {
// usort() sorts in place, so apply it to the $data array
usort($chart->data, function($a, $b){
$months = array('Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12);
// We use the $months array to swap from a month abbreviation to a
// numeric value.
// We compare the index of the x property of the objects in the $data array
// the spaceship operator compares and returns -1, 0, 1 as appropriate
return $months[$a->x]<=>$months[$b->x];
});
}
// Output the results.
print_r($shipping_chart_month);
CodePudding user response:
You was close.
The month alias map (Jan => 1, ...) was a good idea.
You just needed to loop though all arrays in the main array
and sort them (by reference).
Note: im using uasort
, but you could also use usort
.
The source array:
$shipping_chart_month = [
[
"name" => "8=>00 AM",
"data" => [
[
"x" => "May",
"y" => 37
],
[
"x" => "Nov",
"y" => 32
],
[
"x" => "Apr",
"y" => 1
],
[
"x" => "Aug",
"y" => 45
],
[
"x" => "Sep",
"y" => 19
],
[
"x" => "Jul",
"y" => 13
],
[
"x" => "Oct",
"y" => 43
],
[
"x" => "Jun",
"y" => 31
],
[
"x" => "Feb",
"y" => 0
],
[
"x" => "Jan",
"y" => 0
],
[
"x" => "Mar",
"y" => 0
]
]
],
[
"name" => "9=>00 AM",
"data" => [
[
"x" => "Apr",
"y" => 26
],
[
"x" => "Oct",
"y" => 84
],
[
"x" => "Sep",
"y" => 35
],
[
"x" => "Jul",
"y" => 26
],
[
"x" => "Feb",
"y" => 6
],
[
"x" => "Nov",
"y" => 96
],
[
"x" => "Mar",
"y" => 10
],
[
"x" => "May",
"y" => 50
],
[
"x" => "Aug",
"y" => 66
],
[
"x" => "Jun",
"y" => 36
],
[
"x" => "Jan",
"y" => 0
]
]
]
];
The sorting:
// The month alias map.
$monthAliasMap = array(
// {month alias} => {sort priority (lower before higher)}
'Jan' => 1,
'Feb' => 2,
'Mar' => 3,
'Apr' => 4,
'May' => 5,
'Jun' => 6,
'Jul' => 7,
'Aug' => 8,
'Sep' => 9,
'Oct' => 10,
'Nov' => 11,
'Dec' => 12,
);
// Note: using each $array in $shipping_chart_month by reference.
foreach ($shipping_chart_month as &$array) {
uasort($array['data'], function ($a, $b) use ($monthAliasMap) {
// $a | $b example:
// array (
// 'x' => 'May',
// 'y' => 37,
// )
// Set the offset we expect the month alias on.
$offset = 'x';
// Get the month alias from a and b.
$aMonthAlias = $a[$offset]; // F.e. "Jan" or "Dec" ...
$bMonthAlias = $b[$offset]; // F.e. "Jan" or "Dec" ...
// Get (map) the sort priority for a and b.
$aPriority = (int)$monthAliasMap[$aMonthAlias]; // F.e. 1 or 2 ...
$bPriority = (int)$monthAliasMap[$bMonthAlias]; // F.e. 1 or 2 ...
// Sort them.
if ($aPriority === $bPriority) {
return 0;
}
// a < b === asc ; a > b === desc
return ($aPriority < $bPriority) ? -1 : 1;
});
}
unset($array); // Release reference.
Result (shortened):
[
0 => [
'name' => '8=>00 AM',
'data' => [
9 => [
'x' => 'Jan',
'y' => 0,
],
8 => [
'x' => 'Feb',
'y' => 0,
],
// ...
1 => [
'x' => 'Nov',
'y' => 32,
],
],
],
1 => [
'name' => '9=>00 AM',
'data' => [
10 => [
'x' => 'Jan',
'y' => 0,
],
4 => [
'x' => 'Feb',
'y' => 6,
],
// ...
5 => [
'x' => 'Nov',
'y' => 96,
],
],
],
];