PHP: сортировка внешнего массива по ключам, а вложенных - по значениям
Понадобилось в задаче. В PHP много красивых функций сортировки, но готового примера не нашёл. Массив, в принципе, может быть и многоуровневым, раз функция сортировки рекурсивная, но мне больше 2 уровней не нужно, данные примерно вот такого плана:
$array = array ( 'pages' => array ('Russian','English US','Greek'), 'os' => array ('Windows','Linux','Android'), 'countries' => array ('USA','Russia','Usraina') );
На верхнем уровне идёт сортировка по ключам, а во вложенных массивах - по значениям, исходные ключи вложенных массивов при этом можно как сохранять, так и нет.
Вот листинг примера и его вывод.
<?php function sortArray (&$a,$nested=false) { //рекурсивная сортировка ассоциативного массива $nested ? asort ($a,SORT_NATURAL|SORT_FLAG_CASE) : ksort($a,SORT_NATURAL|SORT_FLAG_CASE); foreach ($a as $key=>$value) if (is_array($value)) { $a[$key] = sortArray($value,true); } return $a; } function printArray (&$a) { //рекурсивная печать ассоциативного массива echo '<blockquote>'."\n"; foreach ($a as $key=>$value) { echo $key.': '."\n"; if (is_array($value)) printArray ($value); else echo htmlspecialchars($value).'<br>'."\n"; } echo '</blockquote>'."\n"; } header('Content-Type: text/html; charset=utf-8'); $array = array ( 'pages' => array ('Russian','English US','Greek'), 'os' => array ('Windows','Linux','Android'), 'countries' => array ('USA','Russia','Usraina') ); sortArray ($array); printArray ($array); ?>
countries: 1: Russia 0: USA 2: Usraina os: 2: Android 1: Linux 0: Windows pages: 1: English US 2: Greek 0: Russian
Массив функцией sortArray
получен по ссылке, но оператор return $a;
в функции нужен, так как
сортируются и помещаются "на место" вложенные элементы-массивы. Поэтому для большого объёма данных подход нежелателен.
Если надо "перебить", а не сохранить ключи во вложенных массивах,
замените в sortArray
вызов asort
на sort
.
Данные не обязательно закодированы в Юникоде, но если оставить директиву header
,
то на ряде локальных серверов, таких как Denwer, в папке скрипта нужен и файл
.htaccess
с указанием
AddDefaultCharset utf-8
Можно было бы всё делать через лучшую функцию сортировки uasort
, применив пользовательскую функцию сравнения 2 элементов как здесь:
<?php function trimall ($string) { //убрать лишние разделители return preg_replace("/(^\s*)|(\s*$)/","",preg_replace("/\s+/"," ",trim($string))); } function cmp ($a0,$b0) { //сравнение 2 элементов как строк Юникода, с игнорированием регистра $a = mb_strtolower(trimall(''.$a0),'UTF-8'); $b = mb_strtolower(trimall(''.$b0),'UTF-8'); $alen = mb_strlen ($a,'UTF-8'); $blen = mb_strlen ($b,'UTF-8'); for ($i=0; $i<min($alen,$blen); $i++) { $ca = mb_substr ($a, $i, 1, 'UTF-8'); $cb = mb_substr ($b, $i, 1, 'UTF-8'); if ($ca<$cb) return -1; else if ($ca>$cb) return 1; } if ($alen<$blen) return -1; else if ($alen>$blen) return 1; else return 0; } function sortArray (&$a) { //рекурсивная сортировка ассоциативного массива uasort ($a,'cmp'); foreach ($a as $key=>$value) if (is_array($value)) { $a[$key] = sortArray($value); } return $a; } header('Content-Type: text/html; charset=utf-8'); $array = array ( 'pages' => array ('Russian','English US','Greek'), 'os' => array ('Windows','Linux','Android'), 'countries' => array ('USA','Russia','Usraina') ); sortArray ($array); echo '<pre>'; print_r ($array); echo '</pre>'; ?>
Рекурсивная сортировка в sortArray
стала выглядеть наглядней, не так ли? Зато посимвольный разбор строк Юникода будет явно медленней стандартного.
Вот что вышло (последний листинг печатает массив стандартной функцией print_r
):
Array ( [countries] => Array ( [1] => Russia [0] => USA [2] => Usraina ) [os] => Array ( [2] => Android [1] => Linux [0] => Windows ) [pages] => Array ( [1] => English US [2] => Greek [0] => Russian ) )
Тут уже существенней, что данные должны быть именно в Юникоде, это предполагает функция cmp
.
06.01.2017, 16:47 [4917 просмотров]