БлогNot. PHP: сортировка внешнего массива по ключам, а вложенных - по значениям

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 просмотров]


теги: php алгоритм

К этой статье пока нет комментариев, Ваш будет первым