- Изучаем PHP: сортировка массива
- A – Сортировка по оценке (параметр grade) (числовая сортировка)
- Массив в виде
- Массив отсортирован по оценке
- B – Сортировка по имени (в алфавитном порядке)
- Массив в виде
- Массив отсортирован по имени
- Сортировка массивов
- User Contributed Notes 2 notes
- usort
- Parameters
- Return Values
- Changelog
- Examples
- See Also
- User Contributed Notes 10 notes
Изучаем PHP: сортировка массива
Благодаря своей мощности и гибкости в работе массивы стали непременным атрибутом PHP . Причем, в ряде сложных ситуаций можно задействовать и двумерные массивы PHP . Данная статья посвящена сортировке многомерных массивов в PHP .
- Многомерный массив;
- Встроенные функции PHP usort () , uasort () или uksort () ;
- Встроенные функции PHP strcasecmp() или strcmp() .
Реализация :
Допустим что, у нас есть массив:
$students = array ( 1 => array ('name' => 'Jack', 'grade' => 98.5), 2 => array ('name' => 'Bill', 'grade' => 90.1), 3 => array ('name' => 'Chloe', 'grade' => 94.0), 4 => array ('name' => 'Taylor', 'grade' => 95.1), 5 => array ('name' => 'Larry', 'grade' => 94.6) );
Здесь можно осуществить сортировку двумерного массива PHP по параметру grade ( оценка ) ( числовая сортировка ) или name ( имя ) ( сортировка в алфавитном порядке ).
Внешний массив $students состоит из пяти элементов, каждый из которых также представлен в виде отдельного массива. Внутренний массив использует ID студента в качестве ключа и хранит два значения: имя студента и его оценку.
Для сортировки многомерного массива мы задаем собственную функцию. Говорим PHP , что именно ее нужно использовать для вызова встроенных функций usort () , uasort () или uksort () .
Определяемая функция должна принимать два параметра и возвращать значение, указывающее, какой именно параметр идет первым по списку. Отрицательное или false значение говорит о том, что первый параметр указывается до второго. Положительное или true — что вначале идет второй параметр. Нулевое значение ( 0 ) указывает, что оба параметра равнозначны.
A – Сортировка по оценке (параметр grade) (числовая сортировка)
Определим функцию для сортировки массива по оценке ( параметр grade ):
// Функция сортировки по оценке: сортировка по УБЫВАНИЮ. function grade_sort($x, $y) < if ($x[' оценка '] < $y[' оценка ']) < return true; >else if ($x['оценка'] > $y['оценка']) < return false; >else < return 0; >>
Затем возьмем пользовательскую функцию и осуществим перебор двумерного массива PHP по первому ключу. Выглядит это примерно так:
// $students – наш многомерный массив, а grade_sort – созданная функция usort ($students, ' grade_sort ');
// Вызвать на печать массив в виде (начальный массив): echo 'Массив в виде
' . print_r($students, 1) . ''; // Сортировать по оценке (grade): uasort($students, 'grade_sort'); echo '
Массив отсортирован по оценке
' . print_r($students, 1) . '';
PHP будет отправлять внутренние массивы к этой функции для дальнейшей сортировки. Если вам интересно, как все это происходит в деталях, то выведите на экран результаты сравнения значений внутри функции. А саму функцию после PHP создания двумерного массива измените следующим образом:
function grade_sort($x, $y) < static $count = 1; echo “Iteration $count: vs. n”; $count++; if ($x[‘ оценка ‘] < $y[‘ оценка ‘]) < return true; >else if ($x[‘ключ1′] > $y[‘ключ1′]) < return false; >else < return 0; >>
Выводя на экран значения $x[‘оценка’] и $y [‘оценка’] , можно увидеть, как вызывается функция сортировки, определенная пользователем.
Можно сократить функцию grade_sort следующим образом:
// Функция числовой сортировки по оценке: сортировка по УБЫВАНИЮ function grade_sort($x, $y)
Результаты сортировки двумерного массива PHP по оценке отображены на картинке ниже:
Примечание : Функция usort () сортирует по значениям, но не сохраняет ключи ( для внешнего массива ). Если ключи нужны, то лучше использовать функцию uasort () .
B – Сортировка по имени (в алфавитном порядке)
Чтобы отсортировать массив $students по первому ключу, необходимо сравнить две строки. Поэтому в примере с сортировкой в алфавитном порядке воспользуемся функция strcasecmp() ( не чувствительна к регистру ) и strcmp() ( чувствительна к регистру ). Получившийся двумерный массив PHP будет иметь следующий вид:
// Функция сортировки по имени: function name_sort($x, $y)
// Вывести на печать массив в виде (начальный массив): echo 'Массив в виде
' . print_r($students, 1) . ''; // Сортировка по имени: uasort($students, 'name_sort'); echo '
Массив отсортирован по имени
' . print_r($students, 1) . '';
На скриншоте, приведенном ниже, показан результат сортировки по имени:
Сортировка массивов
В PHP есть несколько функций для сортировки массивов, на этой странице даётся их общее описание.
Основные различия между функциями:
- В одних функциях массивы ( array ) сортируются по ключам элементов, в других по значениям: $array[‘ключ’] = ‘значение’;
- В каких-то функциях связь между ключами и значениями после сортировки сохраняется, в каких-то нет. Это может приводить к тому, что ключи будут сбрасываться в числовые значения (0, 1, 2, . ).
- Различия в порядке сортировки: алфавитный, возрастающий, убывающий, числовой, естественный, случайный или определённый пользователем
- Примечание: Все функции сортировки модифицируют переданный массив, а не возвращают отсортированную копию
- Если какая-либо из этих функций сортировки оценивает два элемента как равные, они сохраняют свой исходный порядок. До PHP 8.0.0 их порядок не был определён (сортировка была нестабильной).
Имя функции | Сортирует по | Сохраняет связь ключ — значение | Порядок сортировки | Похожие функции |
---|---|---|---|---|
array_multisort() | значению | строковые ( string ) ключи да, числовые ( int ) — нет | первый массив или настройки сортировки | array_walk() |
asort() | значению | да | по возрастанию | arsort() |
arsort() | значению | да | по убыванию | asort() |
krsort() | ключу | да | по убыванию | ksort() |
ksort() | ключу | да | по возрастанию | krsort() |
natcasesort() | значению | да | естественный, нечувствительный к регистру | natsort() |
natsort() | значению | да | естественный | natcasesort() |
rsort() | значению | нет | по убыванию | sort() |
shuffle() | значению | нет | случайный | array_rand() |
sort() | значению | нет | по возрастанию | rsort() |
uasort() | значению | да | определяется пользователем | uksort() |
uksort() | ключу | да | определяется пользователем | uasort() |
usort() | значению | нет | определяется пользователем | uasort() |
User Contributed Notes 2 notes
While this may seem obvious, user-defined array sorting functions ( uksort(), uasort(), usort() ) will *not* be called if the array does not have *at least two values in it*.
function usortTest ( $a , $b ) var_dump ( $a );
var_dump ( $b );
return — 1 ;
>
$test = array( ‘val1’ );
usort ( $test , «usortTest» );
$test2 = array( ‘val2’ , ‘val3’ );
usort ( $test2 , «usortTest» );
The first array doesn’t get sent to the function.
Please, under no circumstance, place any logic that modifies values, or applies non-sorting business logic in these functions as they will not always be executed.
Another way to do a case case-insensitive sort by key would simply be:
uksort ( $array , ‘strcasecmp’ );
?>
Since strcasecmp is already predefined in php it saves you the trouble to actually write the comparison function yourself.
usort
Sorts array in place by values using a user-supplied comparison function to determine the order.
Note:
If two members compare as equal, they retain their original order. Prior to PHP 8.0.0, their relative order in the sorted array was undefined.
Note: This function assigns new keys to the elements in array . It will remove any existing keys that may have been assigned, rather than just reordering the keys.
Parameters
The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
Returning non-integer values from the comparison function, such as float , will result in an internal cast to int of the callback’s return value. So values such as 0.99 and 0.1 will both be cast to an integer value of 0 , which will compare such values as equal.
Return Values
Always returns true .
Changelog
Version | Description |
---|---|
8.2.0 | The return type is true now; previously, it was bool . |
8.0.0 | If callback expects a parameter to be passed by reference, this function will now emit an E_WARNING . |
Examples
Example #1 usort() example
foreach ( $a as $key => $value ) echo » $key : $value \n» ;
>
?>
The above example will output:
The spaceship operator may be used to simplify the internal comparison even further.
foreach ( $a as $key => $value ) echo » $key : $value \n» ;
>
?>
Note:
Obviously in this trivial case the sort() function would be more appropriate.
Example #2 usort() example using multi-dimensional array
function cmp ( $a , $b )
return strcmp ( $a [ «fruit» ], $b [ «fruit» ]);
>
?php
$fruits [ 0 ][ «fruit» ] = «lemons» ;
$fruits [ 1 ][ «fruit» ] = «apples» ;
$fruits [ 2 ][ «fruit» ] = «grapes» ;
foreach ( $fruits as $key => $value ) echo «\$fruits[ $key ]: » . $value [ «fruit» ] . «\n» ;
>
?>
When sorting a multi-dimensional array, $a and $b contain references to the first index of the array.
The above example will output:
$fruits[0]: apples $fruits[1]: grapes $fruits[2]: lemons
Example #3 usort() example using a member function of an object
class TestObj private string $name ;
?php
function __construct ( $name )
$this -> name = $name ;
>
/* This is the static comparing function: */
static function cmp_obj ( $a , $b )
return strtolower ( $a -> name ) strtolower ( $b -> name );
>
>
$a [] = new TestObj ( «c» );
$a [] = new TestObj ( «b» );
$a [] = new TestObj ( «d» );
usort ( $a , [ TestObj ::class, «cmp_obj» ]);
foreach ( $a as $item ) echo $item -> name . «\n» ;
>
?>
The above example will output:
Example #4 usort() example using a closure to sort a multi-dimensional array
$array [ 0 ] = array( ‘key_a’ => ‘z’ , ‘key_b’ => ‘c’ );
$array [ 1 ] = array( ‘key_a’ => ‘x’ , ‘key_b’ => ‘b’ );
$array [ 2 ] = array( ‘key_a’ => ‘y’ , ‘key_b’ => ‘a’ );
?php
function build_sorter ( $key ) return function ( $a , $b ) use ( $key ) return strnatcmp ( $a [ $key ], $b [ $key ]);
>;
>
usort ( $array , build_sorter ( ‘key_b’ ));
foreach ( $array as $item ) echo $item [ ‘key_a’ ] . ‘, ‘ . $item [ ‘key_b’ ] . «\n» ;
>
?>
The above example will output:
Example #5 usort() example using the spaceship operator
The spaceship operator allows for straightforward comparison of compound values across multiple axes. The following example will sort $people by last name, then by first name if the last name matches.
$people [ 0 ] = [ ‘first’ => ‘Adam’ , ‘last’ => ‘West’ ];
$people [ 1 ] = [ ‘first’ => ‘Alec’ , ‘last’ => ‘Baldwin’ ];
$people [ 2 ] = [ ‘first’ => ‘Adam’ , ‘last’ => ‘Baldwin’ ];
?php
function sorter (array $a , array $b ) return [ $a [ ‘last’ ], $a [ ‘first’ ]] [ $b [ ‘last’ ], $b [ ‘first’ ]];
>
foreach ( $people as $person ) print $person [ ‘last’ ] . ‘, ‘ . $person [ ‘first’ ] . PHP_EOL ;
>
?>
The above example will output:
Baldwin, Adam Baldwin, Alec West, Adam
See Also
- uasort() — Sort an array with a user-defined comparison function and maintain index association
- uksort() — Sort an array by keys using a user-defined comparison function
- The comparison of array sorting functions
User Contributed Notes 10 notes
As the documentation says, the comparison function needs to return an integer that is either «less than, equal to, or greater than zero». There is no requirement to restrict the value returned to -1, 0, 1.
usort ( $array , function( $a , $b ) if( $a -> integer_property > $b -> integer_property ) return 1 ;
>
elseif( $a -> integer_property < $b ->integer_property ) return — 1 ;
>
else return 0 ;
>
>);
?>
can be simplified to
usort ( $array , function( $a , $b ) return $a -> integer_property — $b -> integer_property ;
>);
?>
This of course applies to any comparison function that calculates an integer «score» for each of its arguments to decide which is «greater».
If you need to use usort with a key in the calling method, I wrote this as a utility:
function usort_comparison ( $obj , $method , $key ) $usorter = &new Usort ( $obj , $method , $key );
return array( $usorter , «sort» );
>
class Usort function __construct ( $obj , $method , $key ) $this -> obj = $obj ;
$this -> method = $method ;
$this -> key = $key ;
>
function sort ( $a , $b ) return call_user_func_array (array( $this -> obj , $this -> method ), array( $a , $b , $this -> key ));
>
>
class Foo $items = array( FooBar ( 13 ), FooBar ( 2 ));
public function sorter () usort ( $this — items , usort_comparison ( «Foo» , «_cmp» , «item» ));
>
public static function _cmp ( $a , $b , $key ) return strcasecmp ( $a -> $key , $b -> $key );
>
class FooBar public $item ;
function __construct ( $val ) $this -> item = $val ;
>
>
?>
~ simple example. but in the way I need to use it was the key was used in a switch statement to choose the different member of the object to compare against dynamically (as in, sort by x or y or z)
If you want to sort an array according to another array acting as a priority list, you can use this function.
function listcmp ( $a , $b )
<
global $order ;
foreach( $order as $key => $value )
<
if( $a == $value )
<
return 0 ;
break;
>
$order [ 0 ] = «first» ;
$order [ 1 ] = «second» ;
$order [ 2 ] = «third» ;
$array [ 0 ] = «second» ;
$array [ 1 ] = «first» ;
$array [ 2 ] = «third» ;
$array [ 3 ] = «fourth» ;
$array [ 4 ] = «second» ;
$array [ 5 ] = «first» ;
$array [ 6 ] = «second» ;