Методы сортировки массивов в языке PHP

Раздел: Разработка на PHP -> Работа с массивами

Основные подходы к сортировке массивов в PHP

Наиболее универсальным и эффективным решением для сортировки массивов с произвольными критериями является использование функции usort(). Она позволяет задать пользовательскую функцию сравнения, что даёт полный контроль над порядком элементов. Функция сортирует массив по значениям, модифицируя исходный массив (передаётся по ссылке).


$array = [3, 1, 4, 1, 5, 9];
usort($array, function($a, $b) {
    return $a <=> $b; // космический корабль (PHP 7+)
});
print_r($array);
  
Array
(
    [0] => 1
    [1] => 1
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 9
)
  

Эта функция подходит для любых типов значений: чисел, строк, объектов. Для обратной сортировки достаточно изменить знак в результате сравнения (return $b <=> $a). Основная проблема – необходимость помнить, что исходный массив изменяется. Если требуется сохранить исходный порядок, следует предварительно создать копию.

Как отсортировать массив по значениям без сохранения ключей?

Функции sort() и rsort() сортируют массив по значениям и переиндексируют ключи числовыми значениями. Первая – по возрастанию, вторая – по убыванию.


$fruits = ["lemon", "orange", "banana", "apple"];
sort($fruits);
print_r($fruits);
  
Array
(
    [0] => apple
    [1] => banana
    [2] => lemon
    [3] => orange
)
  

Частая ошибка: передача ассоциативного массива – ключи будут потеряны. Решение: использовать asort() или arsort(), если ключи нужно сохранить.

Как отсортировать ассоциативный массив по значениям с сохранением ключей?

Функции asort() (по возрастанию) и arsort() (по убыванию) сортируют массив по значениям, не меняя соответствия ключей.


$ages = ["Peter" => 32, "John" => 28, "Jane" => 35];
asort($ages);
print_r($ages);
  
Array
(
    [John] => 28
    [Peter] => 32
    [Jane] => 35
)
  

Как отсортировать массив по ключам?

Для сортировки по ключам используются ksort() (по возрастанию) и krsort() (по убыванию).


$colors = ["red" => 3, "blue" => 1, "green" => 2];
ksort($colors);
print_r($colors);
  
Array
(
    [blue] => 1
    [green] => 2
    [red] => 3
)
  

Проблема: при сортировке по ключам с нечисловыми строками порядок может быть неожиданным (регистрозависимость). Для естественной сортировки строк используйте natcasesort().

Как выполнить естественную сортировку строк (человеческий порядок)?

Функции natsort() и natcasesort() сортируют строки, учитывая числовые значения внутри (например, file1, file2, file10). Первая регистрозависима, вторая – нет.


$files = ["file10.txt", "file2.txt", "file1.txt"];
natsort($files);
print_r($files);
  
Array
(
    [2] => file1.txt
    [1] => file2.txt
    [0] => file10.txt
)
  

Ошибка: использование обычной sort() даёт file1, file10, file2. Применение natsort() решает эту проблему.

Как отсортировать многомерный массив по одному из полей?

Для многомерных массивов применяется usort() с функцией сравнения, обращающейся к нужному полю.


$people = [
    ["name" => "John", "age" => 28],
    ["name" => "Jane", "age" => 35],
    ["name" => "Peter", "age" => 32]
];
usort($people, function($a, $b) {
    return $a['age'] <=> $b['age'];
});
print_r($people);
  
Array
(
    [0] => Array
        (
            [name] => John
            [age] => 28
        )
    [1] => Array
        (
            [name] => Peter
            [age] => 32
        )
    [2] => Array
        (
            [name] => Jane
            [age] => 35
        )
)
  

Проблема: при сравнении строковых полей возможна регистрозависимость. Используйте strcasecmp() для регистронезависимого сравнения.

Как одновременно отсортировать несколько массивов?

Функция array_multisort() сортирует несколько массивов или многомерный массив по одному или нескольким критериям.


$names = ["John", "Jane", "Peter"];
$ages = [28, 35, 32];
array_multisort($ages, SORT_ASC, $names, SORT_ASC);
print_r($names);
print_r($ages);
  
Array
(
    [0] => John
    [1] => Peter
    [2] => Jane
)
Array
(
    [0] => 28
    [1] => 32
    [2] => 35
)
  

Здесь сначала сортируются возрасты, затем имена синхронизируются. Важно, чтобы массивы были одинаковой длины.

Ошибка: передача массивов разной длины приводит к ошибке. Всегда проверяйте равенство размеров.

Как отсортировать массив объектов по свойству?

Аналогично многомерным массивам, используется usort() с доступом к свойству объекта.


class Person {
    public $name;
    public $age;
    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
}
$persons = [
    new Person("John", 28),
    new Person("Jane", 35),
    new Person("Peter", 32)
];
usort($persons, function($a, $b) {
    return $a->age <=> $b->age;
});
foreach ($persons as $p) {
    echo $p->name . " - " . $p->age . PHP_EOL;
}
  
John - 28
Peter - 32
Jane - 35
  

Проблема: если свойство недоступно (private), используйте геттеры. Также возможны ошибки типов при сравнении – убедитесь, что сравниваемые значения имеют одинаковый тип.

Как отсортировать массив с пользовательским порядком (не по алфавиту или числу)?

Метод usort() позволяет реализовать любой порядок, например, сортировку по заданному списку приоритетов.


$priorities = ["high" => 1, "medium" => 2, "low" => 3];
$items = [
    ["task" => "Fix bug", "priority" => "high"],
    ["task" => "Add feature", "priority" => "low"],
    ["task" => "Review docs", "priority" => "medium"]
];
usort($items, function($a, $b) use ($priorities) {
    return $priorities[$a['priority']] <=> $priorities[$b['priority']];
});
print_r($items);
  
Array
(
    [0] => Array
        (
            [task] => Fix bug
            [priority] => high
        )
    [1] => Array
        (
            [task] => Review docs
            [priority] => medium
        )
    [2] => Array
        (
            [task] => Add feature
            [priority] => low
        )
)
  

Ошибка: если значение приоритета отсутствует в заданном наборе, возникнет ошибка индекса. Всегда проверяйте наличие ключа.

Расширенные примеры сортировки

Сортировка многомерного массива по нескольким полям

Для сортировки сначала по одному полю, затем по другому, функция сравнения должна возвращать 0 при равенстве первого поля и переходить ко второму.

Пример

$data = [
    ["name" => "John", "age" => 28, "salary" => 50000],
    ["name" => "Jane", "age" => 35, "salary" => 60000],
    ["name" => "Peter", "age" => 28, "salary" => 55000],
    ["name" => "Anna", "age" => 35, "salary" => 62000]
];
usort($data, function($a, $b) {
    $cmp = $a['age'] <=> $b['age'];
    if ($cmp === 0) {
        return $a['salary'] <=> $b['salary'];
    }
    return $cmp;
});
print_r($data);
  
Array
(
    [0] => Array
        (
            [name] => John
            [age] => 28
            [salary] => 50000
        )
    [1] => Array
        (
            [name] => Peter
            [age] => 28
            [salary] => 55000
        )
    [2] => Array
        (
            [name] => Jane
            [age] => 35
            [salary] => 60000
        )
    [3] => Array
        (
            [name] => Anna
            [age] => 35
            [salary] => 62000
        )
)
  

Особенность: при использовании array_multisort можно передать столбцы как отдельные массивы (через array_column), но usort даёт больше гибкости с пользовательскими правилами.

Регистронезависимая сортировка строк

Для сортировки без учёта регистра применяется strcasecmp() в пользовательской функции.

Пример

$fruits = ["Apple", "banana", "Cherry", "avocado"];
usort($fruits, function($a, $b) {
    return strcasecmp($a, $b);
});
print_r($fruits);
  
Array
(
    [0] => Apple
    [1] => avocado
    [2] => banana
    [3] => Cherry
)
  

Обратите внимание, что strcasecmp() возвращает отрицательное, положительное или нулевое значение – идеально для usort().

Сортировка с сохранением исходного порядка равных элементов (стабильная сортировка)

В PHP функции сортировки не гарантируют стабильность (порядок равных элементов может меняться). Для стабильной сортировки можно использовать комбинацию array_multisort с ключами исходного массива.

Пример

$items = [
    ["name" => "A", "group" => 1],
    ["name" => "B", "group" => 2],
    ["name" => "C", "group" => 1],
    ["name" => "D", "group" => 2]
];
$groups = array_column($items, 'group');
$ids = array_keys($items);
array_multisort($groups, SORT_ASC, $ids, SORT_ASC, $items);
print_r($items);
  
Array
(
    [0] => Array
        (
            [name] => A
            [group] => 1
        )
    [1] => Array
        (
            [name] => C
            [group] => 1
        )
    [2] => Array
        (
            [name] => B
            [group] => 2
        )
    [3] => Array
        (
            [name] => D
            [group] => 2
        )
)
  

Добавление сортировки по исходным индексам ($ids) сохраняет первоначальный порядок среди равных групп.

Сортировка чисел в виде строк (естественный порядок с учётом числовых значений)

Использование natsort() уже было показано, но можно реализовать аналогичное поведение с usort() и функцией strnatcmp().

Пример

$versions = ["1.10", "1.2", "1.1", "1.20"];
usort($versions, function($a, $b) {
    return strnatcmp($a, $b);
});
print_r($versions);
  
Array
(
    [0] => 1.1
    [1] => 1.2
    [2] => 1.10
    [3] => 1.20
)
  

Ошибка: сравнение через <=> даёт другой порядок (1.1, 1.10, 1.2, 1.20), так как строки сравниваются лексикографически.

Сортировка массива объектов по нескольким свойствам с помощью замыкания

Можно создать фабрику функций сравнения для повторного использования.

Пример

function makeComparator($fields) {
    return function($a, $b) use ($fields) {
        foreach ($fields as $field => $order) {
            $cmp = $a->$field <=> $b->$field;
            if ($cmp !== 0) return ($order === 'desc') ? -$cmp : $cmp;
        }
        return 0;
    };
}

$persons = [
    (object)['name' => 'John', 'age' => 30],
    (object)['name' => 'Jane', 'age' => 25],
    (object)['name' => 'John', 'age' => 20]
];
usort($persons, makeComparator(['name' => 'asc', 'age' => 'asc']));
print_r($persons);
  
Array
(
    [0] => stdClass Object
        (
            [name] => Jane
            [age] => 25
        )
    [1] => stdClass Object
        (
            [name] => John
            [age] => 20
        )
    [2] => stdClass Object
        (
            [name] => John
            [age] => 30
        )
)
  

Такой подход упрощает сортировку по динамическим наборам полей.

Сортировка многомерного массива с помощью array_multisort и array_column

Для сортировки по столбцу многомерного массива можно извлечь столбец через array_column и использовать array_multisort.

Пример

$inventory = [
    ["product" => "Laptop", "price" => 1000],
    ["product" => "Phone", "price" => 800],
    ["product" => "Tablet", "price" => 600]
];
$prices = array_column($inventory, 'price');
array_multisort($prices, SORT_DESC, $inventory);
print_r($inventory);
  
Array
(
    [0] => Array
        (
            [product] => Laptop
            [price] => 1000
        )
    [1] => Array
        (
            [product] => Phone
            [price] => 800
        )
    [2] => Array
        (
            [product] => Tablet
            [price] => 600
        )
)
  

Примечание: при использовании array_multisort важно, чтобы массив столбцов имел те же ключи, что и исходный массив (числовые). Если в исходном массиве ключи не последовательные, сортировка может нарушиться. В таких случаях лучше использовать usort().

Сортировка в PHP - comments

En
Index php sort (php)