Php отсортировать двумерный массив по ключу. Сортировка многомерного массива в PHP
Благодаря своей мощности и гибкости в работе массивы стали непременным атрибутом PHP . Причем, в ряде сложных ситуаций можно задействовать и двумерные массивы PHP . Данная статья посвящена сортировке многомерных массивов в PHP .
Составляющие :
- Многомерный массив;
- Встроенные функции PHP usort () , uasort () или uksort () ;
- Встроенные функции PHP strcasecmp() или strcmp() .
Реализация
:
Допустим что, у нас есть массив:
$students = array (1 => array ("name" => "Jack", "grade" => 98.5), 2 => array ("name" => "Bill", "grade" => 90.1), 3 => array ("name" => "Chloe", "grade" => 94.0), 4 => array ("name" => "Taylor", "grade" => 95.1), 5 => array ("name" => "Larry", "grade" => 94.6));
Здесь можно осуществить сортировку двумерного массива PHP по параметру grade (оценка ) (числовая сортировка ) или name (имя ) (сортировка в алфавитном порядке ).
Внешний массив $students состоит из пяти элементов, каждый из которых также представлен в виде отдельного массива. Внутренний массив использует ID студента в качестве ключа и хранит два значения: имя студента и его оценку.
Для сортировки многомерного массива мы задаем собственную функцию. Говорим PHP , что именно ее нужно использовать для вызова встроенных функций usort () , uasort () или uksort () .
Определяемая функция должна принимать два параметра и возвращать значение, указывающее, какой именно параметр идет первым по списку. Отрицательное или false значение говорит о том, что первый параметр указывается до второго. Положительное или true — что вначале идет второй параметр. Нулевое значение (0 ) указывает, что оба параметра равнозначны.
A – Сортировка по оценке (параметр grade) (числовая сортировка)
Определим функцию для сортировки массива по оценке (параметр grade ):
// Функция сортировки по оценке: сортировка по УБЫВАНИЮ. function grade_sort($x, $y) { if ($x[" оценка "] < $y[" оценка "]) { return true; } else if ($x["оценка"] > $y["оценка"]) { return false; } else { return 0; } }
Затем возьмем пользовательскую функцию и осуществим перебор двумерного массива PHP по первому ключу. Выглядит это примерно так:
// $students – наш многомерный массив, а grade_sort – созданная функция usort ($students, " grade_sort ");
Пример :
// Вызвать на печать массив в виде (начальный массив): echo "
Массив в виде
" . print_r($students, 1) . ""; // Сортировать по оценке (grade): uasort($students, "grade_sort"); echo "
Массив отсортирован по оценке
" . print_r($students, 1) . "";
PHP будет отправлять внутренние массивы к этой функции для дальнейшей сортировки. Если вам интересно, как все это происходит в деталях, то выведите на экран результаты сравнения значений внутри функции. А саму функцию после PHP создания двумерного массива измените следующим образом:
function grade_sort($x, $y) { static $count = 1; echo “
Iteration $count: {$x[‘оценка’]} vs. {$y[‘оценка’]}
n”; $count++; if ($x[‘ оценка ‘] < $y[‘ оценка ‘]) { return true; } else if ($x[‘ключ1′] > $y[‘ключ1′]) { return false; } else { return 0; } }Выводя на экран значения $x[‘оценка’] и $y [‘оценка’] , можно увидеть, как вызывается функция сортировки, определенная пользователем.
Можно сократить функцию grade_sort следующим образом:
// Функция числовой сортировки по оценке: сортировка по УБЫВАНИЮ function grade_sort($x, $y) { return ($x["grade"] < $y["grade"]); }
Результаты сортировки двумерного массива PHP по оценке отображены на картинке ниже:
Примечание : Функция usort () сортирует по значениям, но не сохраняет ключи (для внешнего массива ). Если ключи нужны, то лучше использовать функцию uasort () .
B – Сортировка по имени (в алфавитном порядке)
Чтобы отсортировать массив $students по первому ключу, необходимо сравнить две строки. Поэтому в примере с сортировкой в алфавитном порядке воспользуемся функция strcasecmp() (не чувствительна к регистру ) и strcmp() (чувствительна к регистру ). Получившийся двумерный массив PHP будет иметь следующий вид.
Я хотел бы добавить свое собственное решение здесь, так как оно предлагает функции, которые другие ответы не имеют.
В частности, преимущества этого решения включают:
- Он многоразовый : вы указываете столбец сортировки как переменную, а не hardcoding.
- гибкий : вы можете указать несколько столбцов сортировки (сколько угодно) - дополнительные столбцы используются в качестве разделителей между элементами, которые первоначально сравнивают одинаковые.
- обратимый : вы можете указать, что сортировка должна быть отменена - индивидуально для каждого столбца.
- расширяемый : если в наборе данных содержатся столбцы, которые не могут быть сопоставлены "немым" способом (например, строками даты), вы также можете указать, как преобразовать эти элементы в значение, которое может быть напрямую (например, экземпляр DateTime).
- ассоциативно, если вы хотите : этот код выполняет сортировку элементов, но вы выбираете фактическую функцию сортировки (usort или uasort).
- Наконец, он не использует array_multisort: в то время как array_multisort удобно, это зависит от создания проекции всех ваших входных данных перед сортировкой. Это потребляет время и память и может быть просто запретительным, если ваш набор данных большой.
Код
function make_comparer() { // Normalize criteria up front so that the comparer finds everything tidy $criteria = func_get_args(); foreach ($criteria as $index => $criterion) { $criteria[$index] = is_array($criterion) ? array_pad($criterion, 3, null) : array($criterion, SORT_ASC, null); } return function($first, $second) use (&$criteria) { foreach ($criteria as $criterion) { // How will we compare this round? list($column, $sortOrder, $projection) = $criterion; $sortOrder = $sortOrder === SORT_DESC ? -1: 1; // If a projection was defined project the values now if ($projection) { $lhs = call_user_func($projection, $first[$column]); $rhs = call_user_func($projection, $second[$column]); } else { $lhs = $first[$column]; $rhs = $second[$column]; } // Do the actual comparison; do not return if equal if ($lhs < $rhs) { return -1 * $sortOrder; } else if ($lhs > $rhs) { return 1 * $sortOrder; } } return 0; // tiebreakers exhausted, so $first == $second }; }Как использовать
$data = array(array("zz", "name" => "Jack", "number" => 22, "birthday" => "12/03/1980"), array("xx", "name" => "Adam", "number" => 16, "birthday" => "01/12/1979"), array("aa", "name" => "Paul", "number" => 16, "birthday" => "03/11/1987"), array("cc", "name" => "Helen", "number" => 44, "birthday" => "24/06/1967"),);
Основы
Функция make_comparer принимает переменное количество аргументов, которые определяют нужный тип, и возвращает функцию, которую вы должны использовать в качестве аргумента для usort или uasort .
Простейшим вариантом использования является передача ключа, который вы хотите использовать для сравнения элементов данных. Например, чтобы отсортировать $data с помощью элемента name , который вы делаете
Usort($data, make_comparer("name"));
Ключ может также быть числом, если элементы представляют собой числовые индексированные массивы. Для примера в вопросе это будет
Usort($data, make_comparer(0)); // 0 = first numerically indexed column
Несколько столбцов сортировки
Вы можете указать несколько столбцов сортировки, передав дополнительные параметры make_comparer . Например, для сортировки по "числу", а затем по столбцу с нулевой индексацией:
Usort($data, make_comparer("number", 0));
Расширенные функции
Дополнительные функции доступны, если вы укажете столбец сортировки как массив вместо простой строки. Этот массив должен быть численно проиндексирован и должен содержать следующие элементы:
0 => the column name to sort on (mandatory) 1 => either SORT_ASC or SORT_DESC (optional) 2 => a projection function (optional)
Посмотрим, как мы можем использовать эти функции.
Обратный сортировка
Сортировка по имени по убыванию:
Usort($data, make_comparer(["name", SORT_DESC]));
Для сортировки по убыванию номера, а затем по имени:
Usort($data, make_comparer(["number", SORT_DESC], ["name", SORT_DESC]));
Пользовательские прогнозы
В некоторых сценариях вам может понадобиться сортировать по столбцу, значения которого не позволяют хорошо сортировать. Столбец "День рождения" в наборе образцов данных соответствует этому описанию: нет смысла сравнивать дни рождения как строки (потому что "01/01/1980" предшествует "10/10/1970"). В этом случае мы хотим указать, как проецировать фактические данные в форму, которую можно напрямую сравнивать с желаемой семантикой.
Проекции могут быть указаны как любой тип callable : как строки, массивы или анонимные функции. Предполагается, что проекция принимает один аргумент и возвращает его проецируемую форму.
Следует отметить, что в то время как прогнозы похожи на пользовательские функции сравнения, используемые с usort и семейством, они проще (вам нужно только преобразовать одно значение в другое) и использовать все функции, уже запеченные в make_comparer .
Позвольте отсортировать набор данных примера без проекции и посмотреть, что произойдет:
Usort($data, make_comparer("birthday"));
Это не был желаемый результат. Но мы можем использовать date_create в качестве проекции:
Usort($data, make_comparer(["birthday", SORT_ASC, "date_create"]));
Это правильный порядок, который мы хотели.
Есть много других вещей, которые могут достичь прогнозы. Например, быстрый способ получить регистр без учета регистра - использовать strtolower в качестве проекции.
Тем не менее, я должен также упомянуть, что лучше не использовать прогнозы, если ваш набор данных велик: в этом случае было бы намного быстрее проецировать все ваши данные вручную, а затем сортировать, не используя проекцию, хотя делать поэтому будет увеличивать использование памяти для более быстрой скорости сортировки.
Наконец, вот пример, который использует все функции: он сначала сортируется по убыванию числа, а по возрастанию по дням:
Usort($data, make_comparer(["number", SORT_DESC], ["birthday", SORT_ASC, "date_create"]));
Последнее обновление: 1.11.2015
Функция is_array
Функция is_array() проверяет, является ли переменная массивом, и если является, то возвращает true , иначе возвращает false . Например:
$isar = is_array($technics); echo ($isar==true)?"это массив":"это не массив";
Функции count/sizeof
Функция count() и sizeof() получают количество элементов массива:
$number = count($technics); // то же самое, что // $number = sizeof($technics); echo "В массиве technics $number элементов";
Функции shuffle
Функция shuffle перемешивает элементы массивы случайным образом:
$os = array("Windows 95", "Windows XP", "Windows Vista", "Windows 7", "Windows 8", "Windows 10"); shuffle($os); print_r($os); // один из возможных вариантов // Array ( => Windows 95 => Windows 7 => Windows Vista => Windows XP => Windows 10 => Windows 8)
Функции compact
Функция compact позволяет создать из набора переменных ассоциативный массив, где ключами будут сами имена переменных:
Apple II => Apple => 1978) ?>
Функция compact получает в скобках набор переменных. Каждая переменная указывается в кавычка без знака $. Результатом функции является новый массив.
Сортировка массивов
В PHP имеются два типа сортировки: сортировка строк по алфавиту и сортировка чисел по возрастанию/убыванию. Если сортируемые значения представляют строки, то они сортируются по алфавиту, если числа - то они сортируются в порядке возрастания чисел. PHP по умолчанию самостоятельно выбирает тип сортировки.
Для сортировки по возрастанию используется функция asort :
"Lenovo IdeaTab A3500", "samsung" => "Samsung Galaxy Tab 4", "apple" => "Apple iPad Air"); asort($tablets); echo "
- ";
foreach ($tablets as $key => $value)
{
echo "
- $key: $value "; } echo "
В данном случае значения массива представляют строки, поэтому PHP выберет сортировку по алфавиту. Однако с помощью дополнительного параметра мы можем явно указать интерпретатору PHP тип сортировки. Данный параметр может принимать три значения:
SORT_REGULAR: автоматический выбор сортировки
SORT_NUMERIC: числовая сортировка
SORT_STRING: сортировка по алфавиту
Укажем явно тип сортировки:
Asort($tablets, SORT_STRING);
Чтобы отсортировать массив в обратном порядке, применяется функция arsort :
Arsort($tablets);
Сортировка по ключам
Функция asort производит сортировку по значениям элементов, но также существует и еще и сортировка по ключам. Она представлена функцией ksort :
Ksort($tablets, SORT_STRING);
Сортировка по ключам в обратном порядке выполняется функцией krsort() :
Krsort($tablets);
Естественная сортировка
Хотя выше описанные функции сортировки прекрасно выполняют свою работу, но их возможностей все-таки недостаточно. Например, отсортируем по возрастанию следующий массив:
Windows 10 => Windows 7 => Windows 8) ?>
Так как значения представляют строки, то PHP сортирует по алфавиту. Однако подобная сортировка не учитывает числа и регистр. Поэтому значение "Windows 10" будет идти в самом начале, а не в конце, как должно было быть. И для решения этой проблемы в PHP есть функция natsort() , которая выполняет естественную сортировку:
Windows 7 => Windows 8 => Windows 10) ?>
Если нам надо еще при этом, чтобы сортировка не учитывала регистр, то мы можем применить функцию natcasesort() .