MidТеория4 min

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

sort, asort, ksort, usort, stable sort, сравнение

Обзор функций сортировки

Все функции сортировки в PHP модифицируют массив на месте (in-place) и возвращают true/false.

Функция По чему Порядок Связь ключ-значение
sort() Значениям Возрастание Не сохраняется
rsort() Значениям Убывание Не сохраняется
asort() Значениям Возрастание Сохраняется
arsort() Значениям Убывание Сохраняется
ksort() Ключам Возрастание Сохраняется
krsort() Ключам Убывание Сохраняется
usort() Пользов. Пользов. Не сохраняется
uasort() Пользов. Пользов. Сохраняется
uksort() Ключам (пользов.) Пользов. Сохраняется

sort и rsort

<?php
declare(strict_types=1);

$fruits = ['cherry', 'apple', 'banana'];

// sort — ascending, reindexes keys
sort($fruits);
// [0 => 'apple', 1 => 'banana', 2 => 'cherry']

// rsort — descending, reindexes keys
rsort($fruits);
// [0 => 'cherry', 1 => 'banana', 2 => 'apple']

// Sorting flags
$mixed = ['10', '9', '100', '1'];

sort($mixed);  // Default: ['1', '10', '100', '9'] — string comparison!
sort($mixed, SORT_NUMERIC);   // [1, 9, 10, 100]
sort($mixed, SORT_NATURAL);   // ['1', '9', '10', '100'] — natural order
sort($mixed, SORT_STRING);    // ['1', '10', '100', '9'] — lexicographic
sort($mixed, SORT_LOCALE_STRING); // Locale-aware string sort
sort($mixed, SORT_FLAG_CASE | SORT_STRING); // Case-insensitive

Ловушка экзамена: По умолчанию sort() сравнивает элементы как строки, если массив смешанный. ['10', '9'] при sort() без флагов даст ['10', '9'] (строка '10' < '9' лексикографически). Используйте SORT_NUMERIC для числовой сортировки.

asort и arsort

<?php
declare(strict_types=1);

$scores = ['alice' => 85, 'bob' => 92, 'charlie' => 78];

// asort — sort by VALUES, PRESERVE keys
asort($scores);
// ['charlie' => 78, 'alice' => 85, 'bob' => 92]

// arsort — reverse sort by values, preserve keys
arsort($scores);
// ['bob' => 92, 'alice' => 85, 'charlie' => 78]

Запомни: sort() переиндексирует ключи (теряет связь). asort() сохраняет связь ключ-значение. Используйте asort для ассоциативных массивов, sort — для индексированных.

ksort и krsort

<?php
declare(strict_types=1);

$config = [
    'zebra' => 1,
    'alpha' => 2,
    'beta' => 3,
];

// ksort — sort by KEYS ascending
ksort($config);
// ['alpha' => 2, 'beta' => 3, 'zebra' => 1]

// krsort — sort by keys descending
krsort($config);
// ['zebra' => 1, 'beta' => 3, 'alpha' => 2]

// Numeric keys
$arr = [3 => 'c', 1 => 'a', 2 => 'b'];
ksort($arr);
// [1 => 'a', 2 => 'b', 3 => 'c']

Пользовательская сортировка: usort, uasort, uksort

<?php
declare(strict_types=1);

// usort — custom comparison, REINDEXES keys
$users = [
    ['name' => 'Charlie', 'age' => 30],
    ['name' => 'Alice', 'age' => 25],
    ['name' => 'Bob', 'age' => 35],
];

usort($users, fn(array $a, array $b): int => $a['age'] <=> $b['age']);
// Sorted by age ascending

// Multi-level sort
usort($users, function (array $a, array $b): int {
    return $a['name'] <=> $b['name']
        ?: $a['age'] <=> $b['age'];
});

// uasort — custom comparison, PRESERVES keys
$scores = ['alice' => 85, 'bob' => 92, 'charlie' => 78];
uasort($scores, fn(int $a, int $b): int => $b <=> $a);  // Descending
// ['bob' => 92, 'alice' => 85, 'charlie' => 78]

// uksort — sort by keys with custom comparison
$data = ['item_10' => 'a', 'item_2' => 'b', 'item_1' => 'c'];
uksort($data, fn(string $a, string $b): int => strnatcmp($a, $b));
// ['item_1' => 'c', 'item_2' => 'b', 'item_10' => 'a']

Правила callback для сортировки

<?php
declare(strict_types=1);

// Callback MUST return:
// Negative (<0): $a should come before $b
// Zero (0): $a and $b are equal
// Positive (>0): $b should come before $a

// Spaceship operator is ideal for this
$compare = fn(int $a, int $b): int => $a <=> $b;  // Ascending
$compare = fn(int $a, int $b): int => $b <=> $a;  // Descending

// WRONG: returning bool (deprecated in PHP 8.0+)
// usort($arr, fn($a, $b) => $a > $b);  // Don't do this!
// It must return int, not bool

Ловушка экзамена: Callback для usort должен возвращать int (-1, 0, 1). Возвращение bool (как $a > $b) вызовет предупреждение в PHP 8.0+ и даст некорректные результаты. Всегда используйте оператор <=>.

Стабильная сортировка

Начиная с PHP 8.0, все функции сортировки стабильны (stable sort): элементы с одинаковым значением сохраняют свой относительный порядок.

<?php
declare(strict_types=1);

// PHP 8.0+: stable sort
$items = [
    ['name' => 'Alice', 'grade' => 'A'],
    ['name' => 'Bob', 'grade' => 'B'],
    ['name' => 'Charlie', 'grade' => 'A'],
];

usort($items, fn(array $a, array $b): int => $a['grade'] <=> $b['grade']);
// Alice comes before Charlie (both grade A) — original order preserved!
// [Alice(A), Charlie(A), Bob(B)]

// Before PHP 8.0: sort was NOT stable
// Equal elements could appear in any order

Запомни: С PHP 8.0 все функции сортировки стабильны. До PHP 8.0 — НЕТ гарантии стабильности. На экзамене могут спросить об этом изменении.

array_multisort

<?php
declare(strict_types=1);

// Sort multiple arrays simultaneously
$names = ['Charlie', 'Alice', 'Bob'];
$ages = [30, 25, 35];

array_multisort($names, SORT_ASC, $ages);
// $names = ['Alice', 'Bob', 'Charlie']
// $ages  = [25, 35, 30] — reordered to match names!

// Sort by multiple columns
$data = [
    ['name' => 'Alice', 'age' => 25],
    ['name' => 'Bob', 'age' => 25],
    ['name' => 'Alice', 'age' => 30],
];

$nameCol = array_column($data, 'name');
$ageCol = array_column($data, 'age');

array_multisort($nameCol, SORT_ASC, $ageCol, SORT_ASC, $data);
// Sorted by name ASC, then age ASC

Натуральная сортировка

<?php
declare(strict_types=1);

$files = ['file10.txt', 'file2.txt', 'file1.txt', 'file20.txt'];

// Regular sort (lexicographic)
sort($files);
// ['file1.txt', 'file10.txt', 'file2.txt', 'file20.txt']

// Natural sort
natsort($files);
// [2 => 'file1.txt', 1 => 'file2.txt', 0 => 'file10.txt', 3 => 'file20.txt']
// Keys preserved!

// Case-insensitive natural sort
$items = ['IMG10', 'img2', 'IMG1', 'img20'];
natcasesort($items);
// [2 => 'IMG1', 1 => 'img2', 0 => 'IMG10', 3 => 'img20']

// Using SORT_NATURAL flag
sort($files, SORT_NATURAL);
// ['file1.txt', 'file2.txt', 'file10.txt', 'file20.txt']
// Keys reindexed!

Перемешивание и случайность

<?php
declare(strict_types=1);

$arr = [1, 2, 3, 4, 5];

// Shuffle — random order (reindexes keys)
shuffle($arr);

// Random keys
$randomKeys = array_rand($arr, 2);  // 2 random keys

// Reverse
$reversed = array_reverse($arr);         // Values reversed, reindexed
$reversed = array_reverse($arr, true);   // Values reversed, keys preserved

Вопросы с экзамена ZCE

Проверь себя

5 из 17

Какая строка должна заменить `/** line **/`, чтобы вывод был `eeeeee`? ```php function sortByLength($a, $b) { $lenA = strlen($a); $lenB = strlen($b); if ($lenA == $lenB) { return 0; } /** line **/ } $values = ['ccc', 'a', 'eeeeee', 'dddd', 'bb', 'fffff']; usort($values, 'sortByLength'); echo $values[5]; ```

Что вернёт callback сортировки для двух равных элементов?

Какая из следующих функций отсортирует массив по возрастанию значений с сохранением привязки ключей?

Рассмотрите следующий код. Каким будет вывод? ```php $array = array("a1"=>'x', "a2"=>'e', "a3"=>'z'); asort($array); foreach ($array as $keys => $values) { print "$keys = $values"; } ```

Какая функция сортирует по значениям, сохраняя ключи?

Code Challenges

Бинарный поиск

Реализуйте бинарный поиск в отсортированном массиве. Верните индекс элемента или -1, если не найден.

Test Cases

1. Input: [1,3,5,7,9], target=5→ Expected: 2
2. Input: [1,3,5,7,9], target=1→ Expected: 0
3. Input: [1,3,5,7,9], target=9→ Expected: 4
4. Input: [1,3,5,7,9], target=4→ Expected: -1

Слияние отсортированных массивов

Напишите функцию, которая сливает два отсортированных массива в один отсортированный массив.

Test Cases

1. Input: [1,3,5], [2,4,6]→ Expected: [1,2,3,4,5,6]
2. Input: [1,2], [3,4,5,6]→ Expected: [1,2,3,4,5,6]
3. Input: [], [1,2,3]→ Expected: [1,2,3]
4. Input: [1], [1]→ Expected: [1,1]