Как я могу сортировать массивы и данные в PHP?

Из-за огромного и постоянно повторяющегося количества «Как мне сортировать мою уникальную снежинку из массива?» вопросов, это справочная коллекция базовых методов сортировки в PHP. Пожалуйста, закройте любой вопрос, который не сильно отличается как дубликат этого.

Как отсортировать массив в PHP?
Как отсортировать сложный массив в PHP?
Как отсортировать массив объектов в PHP?


  1. Основные одномерные массивы; Включительно Многомерные массивы, вкл. массивы объектов; Включительно Сортировка одного массива на основе другого

  2. Сортировка с SPL

  3. Стабильный сорт

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

Ну, большинство основных методов уже покрыты деменцией, я бы попытался посмотреть на другие типы сортировки

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

SplHeap

 class SimpleHeapSort extends SplHeap { public function compare($a, $b) { return strcmp($a, $b); } } // Let's populate our heap here (data of 2009) $heap = new SimpleHeapSort(); $heap->insert("a"); $heap->insert("b"); $heap->insert("c"); echo implode(PHP_EOL, iterator_to_array($heap)); 

Вывод

 c b a 

SplMaxHeap

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

 $heap = new SplMaxHeap(); $heap->insert(1); $heap->insert(2); $heap->insert(3); 

SplMinHeap

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

 $heap = new SplMinHeap (); $heap->insert(3); $heap->insert(1); $heap->insert(2); 

Другие типы сортировки

Сортировка пузырьков

Из статьи в Википедии о Bubble Сортировка:

Сортировка пузырьков, иногда некорректно называемая погружающейся сортировкой, представляет собой простой алгоритм сортировки, который работает путем многократного перебора сортируемого списка, сравнивая каждую пару соседних элементов и заменяя их, если они находятся в неправильном порядке. Проход по списку повторяется до тех пор, пока не потребуются свопы, что указывает на то, что список отсортирован. Алгоритм получает свое название от того, как меньшие элементы «пузырь» в верхней части списка. Поскольку он использует сравнения для работы с элементами, это сортировка. Хотя алгоритм прост, большинство других алгоритмов сортировки более эффективны для больших списков.

 function bubbleSort(array $array) { $array_size = count($array); for($i = 0; $i < $array_size; $i ++) { for($j = 0; $j < $array_size; $j ++) { if ($array[$i] < $array[$j]) { $tem = $array[$i]; $array[$i] = $array[$j]; $array[$j] = $tem; } } } return $array; } 

Выбор сортировки

Из статьи Википедии о сортировке сортировки:

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

 function selectionSort(array $array) { $length = count($array); for($i = 0; $i < $length; $i ++) { $min = $i; for($j = $i + 1; $j < $length; $j ++) { if ($array[$j] < $array[$min]) { $min = $j; } } $tmp = $array[$min]; $array[$min] = $array[$i]; $array[$i] = $tmp; } return $array; } 

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

Из статьи Википедии о сортировке вставки:

Сортировка вставки – это простой алгоритм сортировки, который формирует окончательный отсортированный массив (или список) по одному элементу за раз. Он гораздо менее эффективен для больших списков, чем более сложные алгоритмы, такие как сортировка quicksort, heapsort или merge. Однако сортировка вставки дает несколько преимуществ:

 function insertionSort(array $array) { $count = count($array); for($i = 1; $i < $count; $i ++) { $j = $i - 1; // second element of the array $element = $array[$i]; while ( $j >= 0 && $array[$j] > $element ) { $array[$j + 1] = $array[$j]; $array[$j] = $element; $j = $j - 1; } } return $array; } 

ShellSort

Из статьи Википедии о Shellsort:

Shellsort, также известный как Shell-сортировка или метод Shell, представляет собой сортировку на месте. Он обобщает сортировку, например, вставку или сортировку пузырьков, путем начала сравнения и обмена элементов с элементами, которые находятся далеко друг от друга, прежде чем заканчивать соседние элементы.

 function shellSort(array $array) { $gaps = array( 1, 2, 3, 4, 6 ); $gap = array_pop($gaps); $length = count($array); while ( $gap > 0 ) { for($i = $gap; $i < $length; $i ++) { $tmp = $array[$i]; $j = $i; while ( $j >= $gap && $array[$j - $gap] > $tmp ) { $array[$j] = $array[$j - $gap]; $j -= $gap; } $array[$j] = $tmp; } $gap = array_pop($gaps); } return $array; } 

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

Из статьи в Википедии, посвященной Comb,

Сорт сортировки – относительно простой алгоритм сортировки, первоначально разработанный Wlodzimierz Dobosiewicz в 1980 году. Позднее он был вновь открыт Стивеном Лэйси и Ричардом Боксом в 1991 году. Сортировка сортировки улучшается по типу пузыря.

 function combSort(array $array) { $gap = count($array); $swap = true; while ( $gap > 1 || $swap ) { if ($gap > 1) $gap /= 1.25; $swap = false; $i = 0; while ( $i + $gap < count($array) ) { if ($array[$i] > $array[$i + $gap]) { // swapping the elements. list($array[$i], $array[$i + $gap]) = array( $array[$i + $gap], $array[$i] ); $swap = true; } $i ++; } } return $array; } 

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

Из статьи Википедии о сортировке Merge:

В информатике сортировка слияния (также обычно называемая mergesort) представляет собой алгоритм сортировки на основе сравнения O (n log n). В большинстве реализаций создается стабильный вид, что означает, что реализация сохраняет порядок ввода равных элементов в отсортированном выходе

 function mergeSort(array $array) { if (count($array) <= 1) return $array; $left = mergeSort(array_splice($array, floor(count($array) / 2))); $right = mergeSort($array); $result = array(); while ( count($left) > 0 && count($right) > 0 ) { if ($left[0] <= $right[0]) { array_push($result, array_shift($left)); } else { array_push($result, array_shift($right)); } } while ( count($left) > 0 ) array_push($result, array_shift($left)); while ( count($right) > 0 ) array_push($result, array_shift($right)); return $result; } 

Quicksort

Из статьи Википедии о Quicksort:

Быстрый сортировка или сортировка разделов – алгоритм сортировки, разработанный Тони Хоаре, который в среднем делает сравнения O (n log n) для сортировки n элементов. В худшем случае он делает сравнения O (n2), хотя это поведение встречается редко.

 function quickSort(array $array) { if (count($array) == 0) { return $array; } $pivot = $array[0]; $left = $right = array(); for($i = 1; $i < count($array); $i ++) { if ($array[$i] < $pivot) { $left[] = $array[$i]; } else { $right[] = $array[$i]; } } return array_merge(quickSort($left), array( $pivot ), quickSort($right)); } 

Перестановка сортировки

Из статьи Википедии о сортировке перестановок:

Сортировка перестановок, которая выполняется путем создания возможных перестановок входного массива / списка до обнаружения отсортированного.

 function permutationSort($items, $perms = array()) { if (empty($items)) { if (inOrder($perms)) { return $perms; } } else { for($i = count($items) - 1; $i >= 0; -- $i) { $newitems = $items; $newperms = $perms; list($foo) = array_splice($newitems, $i, 1); array_unshift($newperms, $foo); $res = permutationSort($newitems, $newperms); if ($res) { return $res; } } } } function inOrder($array) { for($i = 0; $i < count($array); $i ++) { if (isset($array[$i + 1])) { if ($array[$i] > $array[$i + 1]) { return False; } } } return True; } 

Radix sort

Из статьи Википедии о сортировке Radix:

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

 // Radix Sort for 0 to 256 function radixSort($array) { $n = count($array); $partition = array(); for($slot = 0; $slot < 256; ++ $slot) { $partition[] = array(); } for($i = 0; $i < $n; ++ $i) { $partition[$array[$i]->age & 0xFF][] = &$array[$i]; } $i = 0; for($slot = 0; $slot < 256; ++ $slot) { for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) { $array[$i ++] = &$partition[$slot][$j]; } } return $array; } 

Основные одномерные массивы

 $array = array(3, 5, 2, 8); 

Применимые функции сортировки:

  • sort
  • rsort
  • asort
  • arsort
  • natsort
  • natcasesort
  • ksort
  • krsort

Разница между ними заключается лишь в том, сохраняются ли ассоциации с ключом (функции « a »), независимо от того, сортирует ли он от низкого до высокого или наоборот (« r »), сортирует ли он значения или ключи (« k ») и как он сравнивает значения (« nat » и normal). См. http://php.net/manual/en/array.sorting.php для обзора и ссылки на дополнительную информацию.

Многомерные массивы, включая массивы объектов

 $array = array( array('foo' => 'bar', 'baz' => 42), array('foo' => ..., 'baz' => ...), ... ); 

Если вы хотите отсортировать $array по ключу «foo» для каждой записи, вам нужна пользовательская функция сравнения . Вышеупомянутые sort и связанные функции работают с простыми значениями, которые они умеют сравнивать и сортировать. PHP не просто «знает», что делать со сложным значением типа array('foo' => 'bar', 'baz' => 42) ; поэтому вам нужно сказать об этом.

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

 function cmp(array $a, array $b) { if ($a['foo'] < $b['foo']) { return -1; } else if ($a['foo'] > $b['foo']) { return 1; } else { return 0; } } 

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

Затем вы используете одну из следующих функций:

  • usort
  • uasort
  • uksort

Опять же, они отличаются только тем, сохраняют ли они ассоциации ключевых значений и сортируют по значениям или ключам. Прочтите их документацию для деталей.

Пример использования:

 usort($array, 'cmp'); 

usort возьмет два элемента из массива и вызовет с ними функцию cmp . Таким образом, cmp() будет вызываться с $a как array('foo' => 'bar', 'baz' => 42) и $b качестве другого array('foo' => ..., 'baz' => ...) . Затем функция возвращает к usort какие из значений были больше или были равны. usort повторяет этот процесс, передавая разные значения для $a и $b пока массив не будет отсортирован. Функция cmp будет вызываться много раз, по крайней мере столько раз, сколько значений в $array , с разными комбинациями значений для $a и $b каждый раз.

Чтобы привыкнуть к этой идее, попробуйте следующее:

 function cmp($a, $b) { echo 'cmp called with $a:', PHP_EOL; var_dump($a); echo 'and $b:', PHP_EOL; var_dump($b); } 

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

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

сортирует по ссылке и не возвращает ничего полезного!

Обратите внимание, что массив сортируется на месте , вам не нужно присваивать возвращаемое значение чему-либо. $array = sort($array) заменит массив на true , а не на отсортированный массив. Просто sort($array); работает.

Пользовательские числовые сравнения

Если вы хотите отсортировать по ключу baz , который является числовым, все, что вам нужно сделать, это:

 function cmp(array $a, array $b) { return $a['baz'] - $b['baz']; } 

Благодаря The PoWEr oF MATH это возвращает значение <0, 0 или> 0 в зависимости от того, меньше ли $a , равное или большее, чем $b .

Обратите внимание, что это не сработает для значений float , поскольку они будут сведены к int и потеряют точность. Вместо этого используйте явные значения -1 , 0 и 1 .

Объекты

Если у вас есть массив объектов, он работает одинаково:

 function cmp($a, $b) { return $a->baz - $b->baz; } 

функции

Вы можете делать все, что вам нужно, в функции сравнения, включая вызывающие функции:

 function cmp(array $a, array $b) { return someFunction($a['baz']) - someFunction($b['baz']); } 

Струны

Ярлык для первой версии сравнения строк:

 function cmp(array $a, array $b) { return strcmp($a['foo'], $b['foo']); } 

strcmp делает именно то, что ожидается от cmp здесь, оно возвращает -1 , 0 или 1 .

Оператор космического корабля

В PHP 7 появился оператор космического корабля , который унифицирует и упрощает равенство / меньшее / большее, чем сравнение между типами:

 function cmp(array $a, array $b) { return $a['foo'] <=> $b['foo']; } 

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

Если вы хотите сортировать в основном по foo , но если foo равно для двух элементов, baz по baz :

 function cmp(array $a, array $b) { if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) { return $cmp; } else { return $a['baz'] - $b['baz']; } } 

Для знакомых это эквивалентно SQL-запросу с ORDER BY foo, baz .
Также см. Эту очень аккуратную сокращенную версию и как динамически создавать такую ​​функцию сравнения для произвольного количества ключей .

Сортировка в ручной, статический порядок

Если вы хотите отсортировать элементы в «ручном порядке», например «foo», «bar», «baz» :

 function cmp(array $a, array $b) { static $order = array('foo', 'bar', 'baz'); return array_search($a['foo'], $order) - array_search($b['foo'], $order); } 

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

 usort($array, function (array $a, array $b) { return $a['baz'] - $b['baz']; }); 

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

Также для всего вышеперечисленного, чтобы переключаться между восходящим и нисходящим порядком, просто замените аргументы $a и $b . Например:

 return $a['baz'] - $b['baz']; // ascending return $b['baz'] - $a['baz']; // descending 

Сортировка одного массива на основе другого

И тогда есть своеобразный array_multisort , который позволяет сортировать один массив на основе другого:

 $array1 = array( 4, 6, 1); $array2 = array('a', 'b', 'c'); 

Ожидаемый результат здесь:

 $array2 = array('c', 'a', 'b'); // the sorted order of $array1 

Используйте array_multisort чтобы попасть туда:

 array_multisort($array1, $array2); 

Если у вас есть более распространенные случаи, не стесняйтесь редактировать этот ответ.

Стабильный сорт

Допустим, у вас есть такой массив:

 ['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely'] 

И теперь вы хотите отсортировать только по первой букве:

 usort($array, function($a, $b) { return strcmp($a[0], $b[0]); }); 

Результатом является следующее:

 ['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester'] 

Сорт не был стабильным!

Острый наблюдатель, возможно, заметил, что алгоритм сортировки массива (QuickSort) не дал стабильного результата и что первоначальный порядок между словами одной и той же первой буквы не сохранился. Этот случай тривиален, и мы должны были сравнить всю строку, но предположим, что ваш прецедент более сложный, например два последовательных сортировки в разных полях, которые не должны отменять работу друг друга.

Шварцское преобразование

Шварцское преобразование , также называемое идикомой декорации-сортировки-undecorate, оказывает устойчивое сорт с несинхронным алгоритмом сортировки.

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

 array_walk($array, function(&$element, $index) { $element = array($element, $index); // decorate }); 

Это преобразует массив в это:

 [ ['Kale', 0], ['Kaleidoscope', 1], ['Aardvark', 2], ['Apple', 3], ['Leicester', 4], ['Lovely', 5] ] 

Теперь мы корректируем шаг сравнения; мы снова сравниваем первую букву, но если они одинаковы, вторичный ключ используется для сохранения первоначального заказа:

 usort($array, function($a, $b) { // $a[0] and $b[0] contain the primary sort key // $a[1] and $b[1] contain the secondary sort key $tmp = strcmp($a[0][0], $b[0][0]); if ($tmp != 0) { return $tmp; // use primary key comparison results } return $a[1] - $b[1]; // use secondary key }); 

Впоследствии мы решили:

 array_walk($array, function(&$element) { $element = $element[0]; }); 

Конечный результат:

 ['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely'] 

Как насчет повторного использования?

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

 function stablecmp($fn) { return function($a, $b) use ($fn) { if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) { return $tmp; } else { return $a[1] - $b[1]; } }; } 

Давайте будем писать шаг сортировки, используя эту функцию:

 usort($array, stablecmp(function($a, $b) { return strcmp($a[0], $b[0]); })); 

Вуаля! Ваш первоначальный код сравнения вернулся.

Начиная с PHP 5.3 с закрытием, также можно использовать закрытие для определения порядка вашего сортировки.

Например, если предположить, что $ array является массивом объектов, которые содержат свойство месяца.

  $orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec"); usort($array, function($a, $b) use ($orderArray){ return array_search($a->month, $orderArray) - array_search($b->month, $orderArray); }); 

LINQ

В .NET LINQ часто используется для сортировки, которая обеспечивает гораздо более хороший синтаксис над функциями сравнения, особенно когда объекты нужно сортировать по нескольким полям. Существует несколько портов LINQ to PHP, включая библиотеку YaLinqo *. С его помощью массивы можно сортировать по одной строке без написания сложных функций сравнения.

 $sortedByName = from($objects)->orderBy('$v->name'); $sortedByCount = from($objects)->orderBy('$v->count'); $sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name'); 

Сравнение может быть дополнительно настроено путем передачи обратного вызова в качестве второго аргумента, например:

 $sortedByFilenameNat = from($objects)->orderBy('$v->filename', 'strnatcmp'); 

Здесь '$v->count' является сокращением для function ($v) { return $v->count; } function ($v) { return $v->count; } (либо можно использовать). Эти цепочки методов возвращают итераторы, итераторы могут быть преобразованы в массивы, добавив в конец ->toArray() в конце, если это необходимо.

Внутри orderBy и связанные с ним методы вызывают соответствующие функции сортировки массивов ( uasort , krsort , multisort , usort и т. Д.).

LINQ содержит еще много методов, основанных на SQL: фильтрация, группировка, объединение, объединение и т. Д. Это лучше всего подходит для случаев, когда сложные преобразования на массивах и объектах необходимо выполнять без использования баз данных.

*, разработанный мной, см. readme для получения более подробной информации и сравнения с другими портами LINQ

Очень удобно сортировать массивы с отсортированной функцией от Nspl :

Основная сортировка

 // Sort array $sorted = sorted([3, 1, 2]); // Sort array in descending order $sortedDesc = sorted([3, 1, 2], true); 

Сортировка по результату функции

 // Sort array by the result of a given function (order words by length) $sortedByLength = sorted(['bc', 'a', 'abc'], 'strlen'); $sortedByLengthDesc = sorted(['bc', 'a', 'abc'], true, 'strlen'); // Sort array by the result of user-defined function (order words by the 1st character) $sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], function($v) { return $v[0]; }); // Which is the same as $sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], itemGetter(0)); $sortedByTheFirstCharacterDesc = sorted(['bc', 'a', 'abc'], true, itemGetter(0)); // itemGetter(0) returns a function which takes an argument with access by index/key // and returns the value at index 0 

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

 // Sort multidimensional array (sort list of users by their names) $users = [ array('name' => 'Robert', 'age' => 20), array('name' => 'Alex', 'age' => 30), array('name' => 'Jack', 'age' => 25), ]; $sortedByName = sorted($users, itemGetter('name')); $sortedByNameDesc = sorted($users, true, itemGetter('name')); // itemGetter('name') returns a function which takes an argument with access by index/key // and returns the value of the 'name' key 

Сортировка массива объектов

 // Lets assume we have class User(name, age) with properties name and age // and public methods getName() and getAge() $users = [ new User('Robert', 20), new User('Alex', 30), new User('Jack', 25), ]; // Sort list of objects by property value (sort list of users by their name) $sortedByName = sorted($users, propertyGetter('name')); $sortedByNameDesc = sorted($users, true, propertyGetter('name')); // propertyGetter('name') returns a function which takes an object // and returns the value of its 'name' property // Sort list of objects by method result (sort list of users by their age) $sortedByAge = sorted($users, methodCaller('getAge')); $sortedByAgeDesc = sorted($users, true, methodCaller('getAge')); // methodCaller('getAge') returns a function which takes an object // and returns the result of its getAge() method 

Сортировка с функцией сравнения

 // Sort with a comparison function (order words lexicographically with strcmp) $sortedLexicographically = sorted(['bc', 'a', 'abc'], false, null, 'strcmp'); // Sort with user-defined comparison function (order words by the 1st character) $sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], false, null, function($v1, $v2) { return chr($v1[0]) - chr($v2[0]); }); 

Здесь вы можете увидеть все эти примеры.

Самое простое – использовать функцию usort для сортировки массива без каких-либо циклов: Ниже приведен пример:

  $array_compare= array("0" =>4,"1"=>2,"2"=>500,"3"=>100); 

Это будет сортироваться в порядке убывания:

 usort($array_compare, function($a, $b) { return ($b['x1'] - $a['x1']) > 0 ? 1 :-1; }); 

Это будет сортировать по заказу:

 usort($array_compare, function($a, $b) { return ($b['x1'] - $a['x1']) < 0 ? 1 :-1; });