Сортировка 2D массива по столбцу в PHP: разбор "под капотом"

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Магия сортировки: как PHP упорядочивает двумерные массивы

Представьте: у вас есть таблица с данными — список пользователей, товаров или заказов. Вам нужно отсортировать её по возрасту, цене или дате. В Excel это делается одним кликом. А в PHP? Тут начинается самое интересное. Вопрос "Sort a 2d array by a column value" на Stack Overflow набрал тысячи просмотров не просто так — это одна из тех задач, которые встают перед каждым разработчиком.

Сегодня мы не просто дадим готовый код. Мы заглянем "под капот" PHP и разберёмся, как на самом деле работают механизмы сортировки многомерного массива. Вы узнаете, почему usort быстрее циклов, как PHP сравнивает элементы и какие подводные камни ждут новичка. Поехали!

Проблема: почему сортировка 2D массива — это не тривиально?

В PHP есть sort() и asort() для одномерных массивов. Но когда массив становится двумерным (массив массивов), стандартные функции пасуют. Почему? Потому что PHP не знает, по какому именно "столбцу" (ключу внутреннего массива) вы хотите сортировать.

Вот типичный пример:

<?php
$users = [
    ['name' => 'Анна', 'age' => 25],
    ['name' => 'Иван', 'age' => 30],
    ['name' => 'Мария', 'age' => 22]
];
// Как отсортировать по возрасту?
?>

Просто вызвать sort($users)? Нет — PHP выдаст предупреждение и сделает не то, что нужно. Нужен более умный подход.

Решение №1: Классический usort с пользовательской функцией

Самый популярный способ — использовать usort(). Эта функция принимает массив и callback-функцию, которая и определяет порядок сортировки. Давайте разберём её "под капотом".

Как работает usort?

Когда вы вызываете usort($array, $callback), PHP делает следующее:

  • Разбивает массив на пары элементов.
  • Для каждой пары вызывает вашу callback-функцию.
  • Callback должен вернуть: отрицательное число (если первый элемент "меньше"), ноль (если равны), положительное число (если первый "больше").
  • На основе этих ответов PHP переставляет элементы, используя алгоритм быстрой сортировки (Quicksort) или её гибрид.

Вот как это выглядит в коде:

<?php
$users = [
    ['name' => 'Анна', 'age' => 25],
    ['name' => 'Иван', 'age' => 30],
    ['name' => 'Мария', 'age' => 22]
];

usort($users, function($a, $b) {
    return $a['age'] - $b['age'];
});

print_r($users);
// Результат: Мария (22), Анна (25), Иван (30)
?>

Обратите внимание: мы вычитаем возраст $b из $a. Если $a['age'] меньше — результат отрицательный, элемент $a идёт раньше. Просто, как дважды два.

Подводный камень: строки и чувствительность к регистру

Если вы сортируете по строковому полю (например, имени), вычитание не сработает. Нужно использовать strcmp() или strcasecmp() для регистронезависимой сортировки:

<?php
usort($users, function($a, $b) {
    return strcmp($a['name'], $b['name']);
});
// Сортировка по имени (Анна, Иван, Мария)
?>

Но будьте внимательны: strcmp() чувствителен к регистру. "apple" и "Apple" будут считаться разными. Если это критично — используйте strcasecmp().

Решение №2: array_multisort — мощный, но хитрый

Второй популярный способ — array_multisort(). Эта функция умеет сортировать сразу несколько массивов или многомерный массив по одному столбцу. "Под капотом" она работает иначе: она извлекает столбец, сортирует его, а затем переставляет остальные массивы в том же порядке.

Вот как это выглядит:

<?php
$users = [
    ['name' => 'Анна', 'age' => 25],
    ['name' => 'Иван', 'age' => 30],
    ['name' => 'Мария', 'age' => 22]
];

// Извлекаем столбец 'age'
$ages = array_column($users, 'age');

// Сортируем по возрасту
array_multisort($ages, SORT_ASC, $users);

print_r($users);
?>

Что здесь происходит? array_column() создаёт отдельный массив из возрастов. Затем array_multisort() сортирует $ages и применяет тот же порядок к $users. Это похоже на сортировку в Excel: вы сортируете один столбец, а остальные "подтягиваются".

Плюсы и минусы array_multisort

  • Плюс: Можно сортировать по нескольким столбцам сразу (например, сначала по возрасту, потом по имени).
  • Минус: Синтаксис сложнее для новичков. Легко запутаться, какой массив за что отвечает.
  • Минус: Если столбец содержит строки с разной кодировкой, могут быть сюрпризы.

Что быстрее: usort или array_multisort?

Это вечный вопрос. "Под капотом" оба метода используют быструю сортировку, но с разными накладными расходами.

  • usort — вызывает callback для каждой пары элементов. На массиве из 1000 элементов это около 10 000 вызовов функции. Накладные расходы на вызов функции в PHP довольно высоки.
  • array_multisort — использует внутренние C-функции PHP, которые работают быстрее. Но он создаёт копию столбца (через array_column), что увеличивает потребление памяти.

Вывод: Для больших массивов (10 000+ элементов) array_multisort обычно быстрее. Для маленьких — разница незаметна. Если память критична (например, работаете с огромными наборами данных на хостинге с ограничениями), выбирайте usort.

Продвинутый трюк: сортировка по вложенному ключу

Иногда данные имеют более глубокую вложенность. Например, у каждого пользователя есть массив address с ключом city

Блоги

Рекомендаций по книгам