Перейти к содержимому
Теория · Функции для массивов · урок 1 из 8

Сортировка: sort, asort, ksort

Чему вы научитесь

Чему вы научитесь:

  • сортировать массивы через sort, asort и ksort и предсказывать, что станет с ключами;
  • получать из массива новый через array_map, array_filter и array_reduce;
  • искать значения через in_array и array_search и не путать найденный ключ 0 с отсутствием значения;
  • склеивать, резать и разбивать массивы через array_merge, +, array_slice и explode.
Гардероб с крючками [0] и [1], пальто переставлены по длине, стрелки перестановки и табличка sort

В теме о массивах массив был гардеробом: вещи висят на крючках с номерами или с именными бирками. Сам гардероб вещи не перевешивает — для этого нужен персонал.

В PHP персонал гардероба — встроенные функции для массивов. С ними не нужно писать цикл ради каждой мелочи: отсортировать, отобрать или найти вещь можно одной строкой.

Начнём с сортировки. Попросите гардеробщика развесить вещи по порядку, и он переставит их прямо на крючках, а потом скажет «готово». Второй гардероб он вам не выдаст.

Функция sort ведёт себя так же:

PHP
<?php

$prices = [300, 120, 250];
$result = sort($prices);
var_dump($result); // bool(true)
echo implode(' ', $prices), "\n"; // 120 250 300

Давайте разберём по строкам:

  1. $prices = [300, 120, 250]; — список цен вперемешку.
  2. sort($prices) переставляет элементы самого $prices по возрастанию.
  3. В $result попадает не массив, а ответ «готово» — значение true.
  4. var_dump($result) печатает bool(true), а echo выводит склеенные через implode упорядоченные цены 120 250 300.

Сортировка на месте

Сортировка на месте меняет сам переданный массив и не создаёт новый. Так работают все функции сортировки этого урока.

Как вы уже знаете, функция получает копию массива-аргумента и изменить оригинал не может. Исключение — параметр со знаком &: он привязан к самой переменной вызывающего кода. У sort параметр объявлен именно так, поэтому она и переставляет элементы в $prices.

Возвращает sort только признак успеха, а с PHP 8.2 это всегда true. Сохранять его в переменную незачем: пишите sort($prices); отдельной строкой.

Так же ведёт себя usort: она сортирует на месте по вашей функции сравнения и возвращает true. У sort такой функции нет: числа она ставит по возрастанию, строки — по алфавиту, причём заглавные буквы встают раньше строчных.

Что происходит с ключами

Со списком всё понятно: номера крючков остаются 0, 1, 2, а вещи меняются местами. С именными бирками интереснее.

Чтобы увидеть массив вместе с ключами одной строкой, возьмём функцию json_encode. Она записывает массив в JSON — текстовый формат, в котором программы обмениваются данными:

  • список она пишет в квадратных скобках: [5,7,9];
  • массив с любыми другими ключами — в фигурных, с ключами в кавычках: {"pear":7}; такую запись JSON называет объектом.

Отсортируем один и тот же склад тремя способами. Каждая функция получает свою копию $stock, ведь присваивание $a = $stock даёт отдельный массив:

PHP
$stock = ['pear' => 7, 'apple' => 5, 'kiwi' => 9];
$a = $stock;
sort($a);
echo json_encode($a), "\n"; // [5,7,9]
$b = $stock;
asort($b);
echo json_encode($b), "\n"; // {"apple":5,"pear":7,"kiwi":9}
$c = $stock;
ksort($c);
echo json_encode($c), "\n"; // {"apple":5,"kiwi":9,"pear":7}

sort

sort упорядочивает значения и выбрасывает ключи. После неё массив — список с номерами 0, 1, 2. Бирки 'pear' и 'apple' пропали, и уже не узнать, какое число к какому фрукту относилось.

asort

asort тоже упорядочивает значения, но каждый ключ переезжает вместе со своим значением. Буква a в имени означает именно это: связь ключа со значением сохраняется.

ksort

ksort сортирует по ключам: 'apple', 'kiwi' и 'pear' встают по алфавиту, а значения следуют за своими ключами. Буква k в имени означает ключ.

Чем sort отличается от asort и ksort, часто спрашивают на собеседовании. Ответ — ровно эти три подраздела:

  • sort — по значению, без ключей;
  • asort — по значению, с ключами;
  • ksort — по ключу.

Здесь картинка с гардеробом хромает. В настоящем гардеробе номерок всегда остаётся при вещи, а в PHP так поступают только asort и ksort. sort и usort выбрасывают старые бирки и раздают новые номера по порядку.

Обратный порядок

У каждой из трёх функций есть пара с буквой r в имени. Эта пара сортирует в обратную сторону:

  • rsort — значения по убыванию, ключи выбрасываются;
  • arsort — значения по убыванию, ключи сохраняются;
  • krsort — по ключам, в обратном порядке.

array_reverse устроена иначе. Она ничего не сортирует, а переворачивает порядок элементов и возвращает новый массив:

PHP
$nums = [3, 1, 2];
rsort($nums);
echo implode(' ', $nums), "\n"; // 3 2 1
$back = array_reverse($nums);
echo implode(' ', $back), ' ', $nums[0], "\n"; // 1 2 3 3

rsort переставила $nums на месте. array_reverse построила перевёрнутую копию 1 2 3, а в самом $nums первым по-прежнему стоит 3.

Частая ошибка

Ассоциативный массив отсортировали через sort:

PHP
$ages = ['Anna' => 31, 'Ivan' => 25];
sort($ages); // ✗
foreach ($ages as $name => $age) {
    echo $name, ' ', $age, "\n";
}

Программа печатает 0 25 и 1 31, и PHP не выдаёт никаких сообщений. sort выбросила ключи, поэтому имена пропали, а возрасты остались без хозяев. Здесь нужна asort($ages); — тогда цикл напечатает Ivan 25 и Anna 31.

Главное

  • sort, asort, ksort и их пары с r сортируют сам массив на месте и возвращают true, а не новый массив.
  • sort выбрасывает ключи, asort оставляет каждый ключ при его значении, ksort сортирует по ключам.
  • array_reverse не сортирует, а возвращает новый массив в обратном порядке.
  • json_encode показывает массив одной строкой: список — в квадратных скобках, массив с другими ключами — в фигурных.