1. Code
  2. Coding Fundamentals

Как сортировать массивы в PHP

Scroll to top

Russian (Pусский) translation by Pembelight (you can also view the original English article)

Определенную информацию всегда легче получать из отсортированных данных, в обратном случае вам приходится пересматривать по очереди каждый элемент массива. Например, предположим, что вы храните оценки разных учеников одного класса в массиве или таблице.  Если данные не отсортированы по оценкам, вам нужно пересмотреть оценку каждого учащегося, чтобы определить, кто получил самую высокую или или самую низкую. Если данные уже отсортированы от самой низкой к более высокой, то просто взглянув на оценку первого ученика, вы будете знать этот показатель.

Сортировка делает много простых и еффективных задач на основе доступа или получения определенного набора данных. В этом уроке мы узнаем, как использовать встроенные функции PHP для сортировки различных типов массивов.

Сортировка массива по значению

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

Для сортировки значений массива от низкого к высокому вы можете использовать функцию sort(&$array, $sort_flags). Однако, при сортировке массива он не будет поддерживать никаких ассоциаций ключевых значений.  Вместо простой перестановки новые ключи назначаются отсортированным элементам. Необязательный второй параметр указывает порядок сортировки элементов и может иметь шесть разных значений:

  1. SORT_REGULAR - сортировка значений без изменения их типов.
  2. SORT_NUMERIC - сортировка значений путем их численного сравнения.
  3. SORT_STRING - сортировка значений, сравнивая их как стринги.
  4. SORT_LOCALE_STRING - сравнивание значений в виде строки в текущей локалке. Вы можете обновить локалку самостоятельно, используя setlocale().
  5. SORT_NATURAL - сортирует элементы, используя «естественный порядок» и сравнивая их как строки.
  6. SORT_FLAG_CASE - этот параметр можно комбинировать с SORT_STRING или SORT_NATURAL для отключения чувствительности к регистру при сортировке строк.

Вот несколько примеров, которые помогут вам быстро понять разницу между всеми типами сортировки.

1
<?php
2
3
$random_data = [32508, 98134, "234984", "3249832", "38", 123, "Apple"];
4
5
sort($random_data);
6
echo "Regular Sorting  — ";
7
foreach($random_data as $element) {
8
    echo str_pad($element, 9)." ";
9
}
10
// Regular Sorting  — 38        123       32508     98134     234984    3249832   Apple

11
12
sort($random_data, SORT_NUMERIC);
13
echo "\nNumeric Sorting  — ";
14
foreach($random_data as $element) {
15
    echo str_pad($element, 9)." ";
16
}
17
// Numeric Sorting  — Apple     38        123       32508     98134     234984    3249832

18
19
sort($random_data, SORT_STRING);
20
echo "\nString Sorting   — ";
21
foreach($random_data as $element) {
22
    echo str_pad($element, 9)." ";
23
}
24
// String Sorting   — 123       234984    3249832   32508     38        98134     Apple

В примере обычной сортировки числовые строки преобразуются в их числовые значения, и сортировка выполняется соответствующим образом. Строка «Apple» не является числовой, поэтому она остается нетронутой и сравнивается как строка.

Во втором примере наводится числовая сортировка, и мы хотим, чтобы данные сортировались по числовому значению, поэтому «Apple» преобразуется в числовое значение 0 и идет первым. Остальные значения отсортированы ожидаемым образом.

В третьем примере все значения обрабатываются как строки. Это означает, что вместо сравнения числового значения 123 или 3249832 с 38 они сравниваются как строки - по одному символу за раз. Поскольку «1» предшествует «3», значение 123 считается ниже 38.

Если вы хотите отсортировать значения массива от высокого к низкому вместо низкого к высокому, вы можете сделать это с помощью функции rsort().  Он принимает все те же параметры, что и sort(),  сортируя значения в обратном порядке. Он также не поддерживает ассоциации ключевых значений, поэтому это неподходящий способ для сортировки ассоциативных массивов.

Сортировка ассоциативных массивов 

Ассоциации ключевых значений важны, в случае если вы имеете дело с ассоциативными массивами. Рассмотрим следующий пример, где ассоциативный массив используется для хранения имен разных людей и их любимых фруктов.  Если вы хотите отсортировать список в алфавитном порядке по названию фруктов, использование функции sort() из предыдущего раздела приведет к потере ассоциативных ключей.

1
<?php
2
3
$fruit_preferences = ["James" => "Orange", "John" => "Banana", "Patricia" => "Apple", "Jennifer" => "Mango", "Mary" => "Grapes"];
4
5
echo "Before Sorting — \n";
6
foreach($fruit_preferences as $person=>$preference) {
7
    echo $person." likes ".$preference."\n";
8
}
9
10
/*

11
Before Sorting — 

12
James likes Orange

13
John likes Banana

14
Patricia likes Apple

15
Jennifer likes Mango

16
Mary likes Grapes

17
*/
18
19
sort($fruit_preferences);
20
21
echo "After Sorting  — \n";
22
foreach($fruit_preferences as $person=>$preference) {
23
    echo $person." likes ".$preference."\n";
24
}
25
26
/*

27
After Sorting  — 

28
0 likes Apple

29
1 likes Banana

30
2 likes Grapes

31
3 likes Mango

32
4 likes Orange

33
*/
34
35
?>

Как видите, мы не только потеряли взаимосвязь между людьми и их любимыми фруктами, мы также потеряли имена этих людей. Каждому отсортированному значению был присвоен новый числовой индекс, основанный на его позиции в отсортированном массиве.

Чтобы легко решить эту проблему, в PHP есть две разные функции, поддерживающие взаимосвязь между ассоциациями ключевых значений, сортируя массивы по их значениям.  Этими двумя функциями являются asort() и arsort(). Следующий фрагмент кода сортирует тот же массив $fruit_preferences, но использует функцию asort().

1
<?php
2
3
$fruit_preferences = ["James" => "Orange", "John" => "Banana", "Patricia" => "Apple", "Jennifer" => "Mango", "Mary" => "Grapes"];
4
5
echo "Before Sorting — \n";
6
foreach($fruit_preferences as $person=>$preference) {
7
    echo $person." likes ".$preference."\n";
8
}
9
10
/*

11
Before Sorting — 

12
James likes Orange

13
John likes Banana

14
Patricia likes Apple

15
Jennifer likes Mango

16
Mary likes Grapes

17
*/
18
19
asort($fruit_preferences);
20
21
echo "After Sorting  — \n";
22
foreach($fruit_preferences as $person=>$preference) {
23
    echo $person." likes ".$preference."\n";
24
}
25
26
/*

27
After Sorting  — 

28
Patricia likes Apple

29
John likes Banana

30
Mary likes Grapes

31
Jennifer likes Mango

32
James likes Orange

33
*/
34
35
?>

Как видно из приведенного выше примера, значение Apple движется к верху, сохраняя при этом свою связь с Patricia. Названия фруктов можно так же легко сортировать и в обратном порядке, используя функцию arsort().

Обе эти функции принимают те же значения сортировки, как и значения необязательного второго параметра: sort() и rsort().

Сортировка элементов массива по значению с помощью пользовательских функций

С помощью разных значений вашим потребностям могут соответствовать четыре функции сортировки.  Однако иногда ваши критерии сравнения элементов массива могут отличаться.

Допустим, у вас есть массив случайных слов, которые нужно отсортировать по алфавиту.  Но перед этим вы ещё хотите их отсортировать по длине. Например, в традиционной алфавитной сортировке zoo будет следовать за apple.  С другой стороны, если вы хотите показать сначала короткие слова, а потом длинные, то zoo появится перед apple. В том же наборе букв, ape будет перед zoo из-за алфавитного порядка.

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

Для таких случаев PHP предоставляет вам пару функций, которые можно использовать для передачи массива, подлежащий сортировке, вместе с именем вашей собственной функции сортировки.

Используйте функцию usort() для сортировки значений массива в обычных массивах. Точно так же можно использовать функцию uasort() для сортировки значений в ассоциативных массивах, сохраняя при этом ассоциаций ключевых значений.

Этот фрагмент кода показывает один из способов выполнения данной сортировки.

1
<?php
2
3
$random_words = ["ape", "apple", "zoo", "pie", "elephant", "banana", "picnic", "eye"];
4
5
sort($random_words);
6
echo "Regular Sort Function: \n";
7
foreach($random_words as $element) {
8
    echo str_pad($element, 9)." ";
9
}
10
11
/*

12
Regular Sort Function: 

13
ape       apple     banana    elephant  eye       picnic    pie       zoo

14
*/
15
16
function custom_sort($word_a, $word_b) {
17
    if (strlen($word_a) < strlen($word_b)) {
18
        return -1;
19
    }
20
    if (strlen($word_a) == strlen($word_b)) {
21
        return strcmp($word_a, $word_b);
22
    }
23
    if (strlen($word_a) > strlen($word_b)) {
24
        return 1;
25
    }
26
}
27
28
usort($random_words, "custom_sort");
29
echo "\nCustom Sort Function: \n";
30
foreach($random_words as $element) {
31
    echo str_pad($element, 9)." ";
32
}
33
34
/*

35
Custom Sort Function: 

36
ape       eye       pie       zoo       apple     banana    picnic    elephant

37
*/
38
39
?>

В функциях обратного вызова, предназначенных для пользовательской сортировки, мы должны вернуть целое число меньше 0, чтобы указать, что первое значение меньше второго. Если первое значение равно второму, возвращается 0. Если первое значение больше второго, возвращается целое число больше 0.

Поскольку нашим основным критерием сортировки была длина строки, мы напрямую возвращаем -1, если первое слово короче второго.  Точно так же мы возвращаем 1, если первое слово длиннее второго. Когда два слова имеют одинаковую длину, мы сравниваем их в алфавитном порядке с помощью функции strcmp() и возвращаем их значение.

Как вы видите, в результате наша пользовательская функция сортировки переставляет слова в точности так, как мы хотели.

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

Сортировка массива на основе его ключей как всегда полезна, когда вы имеете дело с ассоциативными массивами. Например, у вас может быть массив с информацией общего количества аэропортов в разных странах.  Предполагая, что названия разных стран являются ключами, а количество аэропортов - значениями, вы можете отсортировать названия стран по алфавиту. Это очень легко сделать с помощью функций ksort() и krsort().  Функция ksort() сортирует ключи от низкого к высокому, а krsort() сортирует ключи от высокого к низкому. 

Вот основной пример сортировки:

1
<?php
2
3
$airport_count = ["United States" => 13513, "Brazil" => 4093, "Mexico" => 1714, "Canada" => 1467, "Russia" => 1218, "Argentina" => 1138, "Bolivia" => 855, "Colombia" => 836, "Paraguay" => 799, "Indonesia" => 673];
4
5
ksort($airport_count);
6
7
foreach($airport_count as $country=>$count) {
8
    echo str_pad($country, 15)." ".$count."\n";
9
}
10
11
/*

12
Argentina       1138

13
Bolivia         855

14
Brazil          4093

15
Canada          1467

16
Colombia        836

17
Indonesia       673

18
Mexico          1714

19
Paraguay        799

20
Russia          1218

21
United States   13513

22
*/
23
24
?>

Вместо собственной пользовательской функции для сортировки ключей массива вы можете использовать стандартную PHP функцию uksort(). На ряду usort(), функция обратного вызова в uksort() также требует возврата  целого числа меньше 0, если первый ключ считается меньше второго, и целого числа больше 0, если первый ключ больше второго.  Эта функция также поддерживает ассоциации ключевых значений для элементов массива.

1
<?php
2
3
$airport_count = ["United States" => 13513, "Brazil" => 4093, "Mexico" => 1714, "Canada" => 1467, "Russia" => 1218, "Argentina" => 1138, "Bolivia" => 855, "Colombia" => 836, "Paraguay" => 799, "Indonesia" => 673];
4
5
function custom_sort($word_a, $word_b) {
6
    if (strlen($word_a) < strlen($word_b)) {
7
        return -1;
8
    }
9
    if (strlen($word_a) == strlen($word_b)) {
10
        return strcmp($word_a, $word_b);
11
    }
12
    if (strlen($word_a) > strlen($word_b)) {
13
        return 1;
14
    }
15
}
16
17
uksort($airport_count, "custom_sort");
18
19
foreach($airport_count as $country=>$count) {
20
    echo str_pad($country, 15)." ".$count."\n";
21
}
22
23
/*

24
Brazil          4093

25
Canada          1467

26
Mexico          1714

27
Russia          1218

28
Bolivia         855

29
Colombia        836

30
Paraguay        799

31
Argentina       1138

32
Indonesia       673

33
United States   13513

34
*/
35
36
?>

В приведенном выше примере, чтобы отсортировать названия стран по длине их названия, а затем по алфавиту, мы использовали пользовательскую функцию сортировки из предыдущего раздела.

Сортировка многомерных массивов в PHP

В реальных проектах чаще всего имеют дело с многомерной информацией. Например, учебные заведения будут хранить оценки по разным предметам всех учащихся в одной таблице вместо создания новых таблиц для каждого предмета. Если вам понадобилось бы хранить похожую информацию в PHP, вы тоже предпочли использовать данный подход,а именно  многомерный массив вместо отдельного массива для каждого предмета.

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

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

1
<?php
2
3
$tallest_buildings = [
4
    ["Building" => "Burj Khalifa","City" => "Dubai","Country" => "United Arab Emirates","Height" => 828,"Floors" => 163,"Year" => 2010],
5
    ["Building" => "Shanghai Tower","City" => "Shanghai","Country" => "China","Height" => 632,"Floors" => 128,"Year" => 2015],
6
    ["Building" => "Abraj Al-Bait Towers","City" => "Mecca","Country" => "Saudi Arabia","Height" => 601,"Floors" => 120,"Year" => 2012],
7
    ["Building" => "Ping An Finance Center","City" => "Shenzhen","Country" => "China","Height" => 599,"Floors" => 115,"Year" => 2017],
8
    ["Building" => "Lotte World Tower","City" => "Seoul","Country" => "South Korea" ,"Height" => 554,"Floors" => 123,"Year" => 2016]
9
];
10
11
function storey_sort($building_a, $building_b) {
12
    return $building_a["Floors"] - $building_b["Floors"];
13
}
14
15
usort($tallest_buildings, "storey_sort");
16
17
foreach($tallest_buildings as $tall_building) {
18
    list($building, $city, $country, $height, $floors) = array_values($tall_building);
19
    echo $building." is in ".$city.", ".$country.". It is ".$height." meters tall with ".$floors." floors.\n";
20
}
21
22
/*

23
Ping An Finance Center is in Shenzhen, China. It is 599 meters tall with 115 floors.

24
Abraj Al-Bait Towers is in Mecca, Saudi Arabia. It is 601 meters tall with 120 floors.

25
Lotte World Tower is in Seoul, South Korea. It is 554 meters tall with 123 floors.

26
Shanghai Tower is in Shanghai, China. It is 632 meters tall with 128 floors.

27
Burj Khalifa is in Dubai, United Arab Emirates. It is 828 meters tall with 163 floors.

28
*/
29
30
?>

В приведенном выше примере информация о каждом здании хранится в своем собственном массиве внутри основного массива $tallest_buildings. Функция storey_sort() просто вычитает количество этажей во втором здании, начиная с первого, чтобы определить, какое по нашим критериям здание меньше.  Не следует беспокоиться о возврате определенного отрицательного или положительного значения, потому что все отрицательные значения означают меньшее, а все положительные значения означают большее.

В конце мы просто перебираем основной массив и выводим информацию о каждом здании.

Послесловие

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

Я надеюсь, что в этом уроке вы узнали что-то новое. Если у вас есть какие-либо вопросы или предложения, пожалуйста, сообщите в комментариях. Лучший способ научиться - это попробовать создать собственные примеры сортировки массивов на основе вышеуказанных функций.