Неоднократно сталкивался с проблемой — требовалось отсортировать сформированный двумерный массив по одному из индексов. Решалось просто, всегда спасала функция usort(). Но вот недавно столкнулся с более интересной задачей:
Необходимо получить массив элементов и их описаний из БД. Результат должен быть отсортирован по одному из индексов (ключевой индекс). При этом порядок сортировки может быть по возрастанию или задаваться в соответствии с определенным массивом (массив сортировки).
Например:
Входной массив:
Массив сортировки для индекса 'b'
В принципе все хорошо, сортировать по одному из полей можно без проблем, решается на уровне БД (ORDER BY). Но когда необходимо отсортировать в соответствии с массивом сортировки в голову пришло два варианта.
1. Написать функцию, позволяющую производить подобные манипуляции за счет стандартных функций.
2. Пройти по входному массиву, сформировав новый массив, в качестве ключей которого будут значения индекса 'b'. Далее пройти по массиву сортировки и формировать в прямом порядке результирующий массив.
Лично я выбрал первый вариант, так как легче учесть «подводные камни» и быстродействие.
И так, начнем.
Очевидным является использование все той же функции usort().
Забудем, что данные возвращаются из БД, а значит понадобиться callback-функция, для простой сортировки двумерного массива по ключу. Ее вид таков:
В глобальной переменной $GLOBALS[«my_sort_key»] будет храниться ключевой индекс. Одним из подводных камней могут быть – числа в место строк, но это уже дополнительный обработчик и при желании его можно реализовать, с этим ни у кого проблем не возникнет.
Для сортировки по массиву сортировки необходимо сделать ряд процедур. Для начала необходимо из массива сортировки получить новый «чистый» массив сортировки, где все ключи будут индексированны и упорядочены. Для этого используем функцию array_values(). Далее необходимо написать callback-функцию для сортировки в соответствии с массивом. Она будет иметь вид такой:
В глобальной переменной $GLOBALS[«my_sort_order „] будет храниться чистый массив сортировки. Данная функция находит сравниваемые значения в массиве сортировки, определяет их индексы. После чего уже происходит сравнение индексов и по ним определяется порядок сортировки. Подводным камнем в таком случае может быть отсутствие значения в массиве сортировки. При такой реализации они будут вытесняться в начало массива.
Осталось только объединить вызовы callback-функций и контролировать входные данные.
Эта функция будет иметь примерно такой вид:
Для данной функции обязательными является входной массив и ключевой индекс. Далее создаем глобальную переменную ключевого индекса. Если массив сортировки пустое значение, то вызываем функцию my_sort_no_order() для входного массива. Иначе определяем в глобальной области чистый массив сортировки и вызываем функцию my_sort_order(). После вызова одной из функций сортировки необходимо освободить память от глобальных переменных и вернуть результат работы.
Для приведенного примера результат будет:
Код сильно не прорабатывался, поэтому возможны подводные камни. Но какие? Чего не учел?
Необходимо получить массив элементов и их описаний из БД. Результат должен быть отсортирован по одному из индексов (ключевой индекс). При этом порядок сортировки может быть по возрастанию или задаваться в соответствии с определенным массивом (массив сортировки).
Например:
Входной массив:
$Array = array(
array(
'a' => 26,
'b' => 34,
'c' => 27,
'd' => 16
),
array(
'a' => 65,
'b' => 71,
'c' => 31,
'd' => 17
),
array(
'a' => 30,
'b' => 11,
'c' => 94,
'd' => 19
),
array(
'a' => 73,
'b' => 43,
'c' => 43,
'd' => 12
)
);
Массив сортировки для индекса 'b'
$Key = array(
71,
11,
43,
34
);
В принципе все хорошо, сортировать по одному из полей можно без проблем, решается на уровне БД (ORDER BY). Но когда необходимо отсортировать в соответствии с массивом сортировки в голову пришло два варианта.
1. Написать функцию, позволяющую производить подобные манипуляции за счет стандартных функций.
2. Пройти по входному массиву, сформировав новый массив, в качестве ключей которого будут значения индекса 'b'. Далее пройти по массиву сортировки и формировать в прямом порядке результирующий массив.
Лично я выбрал первый вариант, так как легче учесть «подводные камни» и быстродействие.
И так, начнем.
Очевидным является использование все той же функции usort().
Забудем, что данные возвращаются из БД, а значит понадобиться callback-функция, для простой сортировки двумерного массива по ключу. Ее вид таков:
function my_sort_no_order($a, $b)
{
return strcmp($a[$GLOBALS["my_sort_key"]], $b[$GLOBALS["my_sort_key"]]);
}
В глобальной переменной $GLOBALS[«my_sort_key»] будет храниться ключевой индекс. Одним из подводных камней могут быть – числа в место строк, но это уже дополнительный обработчик и при желании его можно реализовать, с этим ни у кого проблем не возникнет.
Для сортировки по массиву сортировки необходимо сделать ряд процедур. Для начала необходимо из массива сортировки получить новый «чистый» массив сортировки, где все ключи будут индексированны и упорядочены. Для этого используем функцию array_values(). Далее необходимо написать callback-функцию для сортировки в соответствии с массивом. Она будет иметь вид такой:
function my_sort_order($a, $b)
{
$a = array_search($a[$GLOBALS["my_sort_key"]], $GLOBALS["my_sort_order"]);
$b = array_search($b[$GLOBALS["my_sort_key"]], $GLOBALS["my_sort_order"]);
if ($a == $b)
return 0;
return ($a < $b) ? -1 : 1;
}
В глобальной переменной $GLOBALS[«my_sort_order „] будет храниться чистый массив сортировки. Данная функция находит сравниваемые значения в массиве сортировки, определяет их индексы. После чего уже происходит сравнение индексов и по ним определяется порядок сортировки. Подводным камнем в таком случае может быть отсутствие значения в массиве сортировки. При такой реализации они будут вытесняться в начало массива.
Осталось только объединить вызовы callback-функций и контролировать входные данные.
Эта функция будет иметь примерно такой вид:
function my_sort($Array,$Key,$Order=array())
{
if(empty($Array) || empty($Key))
return false;
$GLOBALS["my_sort_key"]=$Key;
if(empty($Order))
usort($Array, "my_sort_no_order");
else
{
$GLOBALS["my_sort_order"] = array_values($Order);
usort($Array, "my_sort_order");
}
unset($GLOBALS["my_sort_order"]);
unset($GLOBALS["my_sort_key"]);
return $Array;
}
Для данной функции обязательными является входной массив и ключевой индекс. Далее создаем глобальную переменную ключевого индекса. Если массив сортировки пустое значение, то вызываем функцию my_sort_no_order() для входного массива. Иначе определяем в глобальной области чистый массив сортировки и вызываем функцию my_sort_order(). После вызова одной из функций сортировки необходимо освободить память от глобальных переменных и вернуть результат работы.
Для приведенного примера результат будет:
array(4) {
[0]=>
array(4) {
["a"]=>
int(65)
["b"]=>
int(71)
["c"]=>
int(31)
["d"]=>
int(17)
}
[1]=>
array(4) {
["a"]=>
int(30)
["b"]=>
int(11)
["c"]=>
int(94)
["d"]=>
int(19)
}
[2]=>
array(4) {
["a"]=>
int(73)
["b"]=>
int(43)
["c"]=>
int(43)
["d"]=>
int(12)
}
[3]=>
array(4) {
["a"]=>
int(26)
["b"]=>
int(34)
["c"]=>
int(27)
["d"]=>
int(16)
}
}
Код сильно не прорабатывался, поэтому возможны подводные камни. Но какие? Чего не учел?