在不同的键上排序多维数组
I have a load of folders and I use DirectoryIterator
to get them into a multidimensional array. The outcome of this is something like this
array:10 [▼
"SomeTitle" => array:2 [▼
2018 => array:3 [▼
"February" => array:4 [▶]
"January" => array:1 [▶]
"March" => array:1 [▶]
]
2017 => array:11 [▼
"February" => array:9 [▶]
"January" => array:12 [▶]
"March" => array:9 [▶]
"September" => array:9 [▶]
"June" => array:8 [▶]
"December" => array:12 [▶]
"October" => array:8 [▶]
"July" => array:10 [▶]
"April" => array:8 [▶]
"August" => array:10 [▶]
"May" => array:10 [▶]
]
]
]
So I have the main key, followed by year, then month, and then some other data.
What I am trying to do is organise the data by year and month. So 2018 should always be first. I then need the months to be organised in month order. At the moment, I am passing the array to this function
function sortArray($arr) {
ksort($arr);
foreach ($arr as $k => $v) {
if (is_array($v)) {
$arr[$k] = $this->sortArray($v);
}
}
return $arr;
}
I dont think I need the ksort as this seems to put 2017 first. When I run the above, I get the following
array:10 [▼
"SomeTitle" => array:2 [▼
2017 => array:11 [▼
"April" => array:8 [▶]
"August" => array:10 [▶]
"December" => array:12 [▶]
"February" => array:9 [▶]
"January" => array:12 [▶]
"July" => array:10 [▶]
"June" => array:8 [▶]
"March" => array:9 [▶]
"May" => array:10 [▶]
"October" => array:8 [▶]
"September" => array:9 [▶]
]
2018 => array:3 [▼
"February" => array:4 [▶]
"January" => array:1 [▶]
"March" => array:1 [▶]
]
]
]
So everything is basically in alphabetical order. Is there any way to change this so the year starts with newest to oldest, and the months are in calendar order?
Thanks
You can use uksort()
to check manually:
- if the keys is a numeric value: sort naturally
- if the keys doesn't match with
strtotime()
sort withstrcmp()
(It could be better to check if the key is equal to a "predefined" month name instead of checkingstrtotime() === false
.) - else sort using
strtotime()
Code:
function sortArray($arr) {
uksort($arr, function($k1, $k2) {
if (is_numeric($k1)) return $k1-$k2 ;
if (strtotime($k1) === false) return strcmp($k1, $k2);
return strtotime($k1) - strtotime($k2);
});
foreach ($arr as $k => $v) {
if (is_array($v)) {
$arr[$k] = $this->sortArray($v);
}
}
return $arr;
}
$array = sortArray($array);
print_r($array);
Outputs:
Array (
[SomeTitle] => Array (
[2017] => Array (
[January] => Array()
[February] => Array()
[March] => Array()
[April] => Array()
[May] => Array()
[June] => Array()
[July] => Array()
[August] => Array()
[September] => Array()
[October] => Array()
[December] => Array()
)
[2018] => Array (
[January] => Array()
[February] => Array()
[March] => Array()
)
)
)
Here is a working demonstration.
Numeric keys corresponding to the month would make more sense, but to do it with the names:
function sortArray($arr) {
krsort($arr);
foreach ($arr as $k => &$v) {
if (is_array($v)) {
array_multisort(array_map(function($m) {
return date('m', strtotime($m));
}, array_keys($v)), $v);
}
}
return $arr;
}
You want krsort
to sort in reverse, then map the array months to get the month number and sort the original on that. Pay attention to &$v
.
You could just use this instead of date
:
return strtotime($m);