Сортировка массива по вычисляемому полю

Задача
Необходимо задать собственную процедуру сортировки.

Решение
Используйте функцию usort() в комбинации с пользовательской
функцией:

// сортируем в порядке, обратном естественному
function natrsort($a, $b) {
return strnatcmp($b, $a);
}
$tests = array('test1.php', 'test10.php', 'test11.php', 'test2.php');
usort($tests, 'natrsort');

Обсуждение
Функция сравнения должна возвращать значение больше 0, если $a > $b, равное 0, если $a == $b и значение меньше 0, если $a < $b. Для сортиров ки в обратном порядке делайте наоборот. Функция strnatcmp(), приведенная в разделе «Решение», подчиняется этим правилам.

Чтобы поменять направление сортировки на обратное, вместо умножения возвращаемого значения strnatcmp($a, $b) на -1 поменяйте местами аргументы в функции strnatcmp($b, $a).
Функции сортировки не обязательно должны быть оболочками существующей сортировки. Например, функция pc_date_sort(), приведенная в примере 4.2, показывает, как сортировать даты.

Пример 4.2. pc_date_sort()
// ожидаем дату в формате "MM/DD/YYYY"
function pc_date_sort($a, $b) {
list($a_month, $a_day, $a_year) = explode('/', $a);
list($b_month, $b_day, $b_year) = explode('/', $b);
if ($a_year > $b_year ) return 1;
if ($a_year < $b_year ) return -1;
if ($a_month > $b_month) return 1;
if ($a_month < $b_month) return -1;
if ($a_day > $b_day ) return 1;
if ($a_day < $b_day ) return -1;
return 0;
}
$dates = array('12/14/2000', '08/10/2001', '08/07/1999');
usort($dates, 'pc_date_sort');

Во время сортировки функция usort() часто – каждый раз, когда ей надо сравнить два элемента – выполняет пересчет значений, возвращаемых функцией сортировки, что замедляет процесс.


Для того чтобы избежать ненужной работы, можно кэшировать сравниваемые значения, как показано в примере 4.3.

Пример 4.3. pc_array_sort()
function pc_array_sort($array, $map_func, $sort_func = '') {
$mapped = array_map($map_func, $array); // cache $map_func() values
if ('' == $sort_func) {
asort($mapped); // функция asort() быстрее функции usort()
} else {
uasort($mapped, $sort_func); // необходимо сохранить ключи
}
while (list($key) = each($mapped)) {
$sorted[] = $array[$key]; // используем отсортированные ключи
}
return $sorted;
}

Чтобы избежать ненужной работы, функция pc_array_sort() использует временный массив $mapped для кэширования возвращаемых значений. Затем она сортирует массив $mapped, используя или порядок сортировки по умолчанию, или определенную пользователем процедуру сортировки. Важно, что она использует сортировку, сохраняющую связи ключ/значение. По умолчанию она использует функцию asort(), потому что она быстрее, чем функция uasort(). (Медленность функции uasort() это все-таки значительный довод в пользу функции pc_array_sort().) Наконец, она создает отсортированный массив $sorted,
при этом отсортированные ключи в массиве $mapped выступают в ка-
честве индексов значений исходного массива.

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


В следующем примере элементы сортируются по длине их строки (это относительно быстрая пользовательская сортировка):

function pc_u_length($a, $b) {
$a = strlen($a);
$b = strlen($b);
if ($a == $b) return 0;
if ($a > $b) return 1;
return -1;
}
function pc_map_length($a) {
return strlen($a);
}
$tests = array('one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'ten');
// для количества элементов < 5 функция pc_u_length() быстрее
usort($tests, 'pc_u_length');
// для количества элементов >= 5 функция pc_map_length() быстрее
$tests = pc_array_sort($tests, 'pc_map_length');

Здесь функция pc_array_sort() быстрее функции usort(), поскольку
массив достигает длины в пять элементов..



Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Добавление одного массива к другому
Изменение длины массива
Инициализация массива диапазоном
Инициализация массива диапазоном целых чисел
Нахождение всех перестановок массива

Вернуться в раздел: PHP / 4. Массивы