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

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

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

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


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

  2. Сортировка с помощью SPL

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

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


person deceze♦    schedule 28.06.2013    source источник
comment
@jterry Именно поэтому я сделал это, чтобы наконец-то получить хороший справочный вопрос, от которого можно отказаться. Ответить на каждую уникальную снежинку по отдельности никому не поможет. :)   -  person deceze♦    schedule 28.06.2013
comment
Я думаю, людям стоит просто взглянуть на php.net   -  person Alexander Jardim    schedule 28.06.2013
comment
@Alex Ha! Абсолютно. Проблема: нет RTFM. : D   -  person deceze♦    schedule 28.06.2013
comment
У нас уже есть эти ответы, я предлагаю вам перечислить лучшие ответы внутри каждого ответа здесь, вместо того, чтобы дублировать (или переписывать) контент. Кроме того, массивы, как правило, видны индивидуально, поэтому в любом случае остается работа, чтобы проголосовать против дублирования.   -  person hakre    schedule 28.06.2013
comment
Можно разместить ссылку на него в вики-странице тегов сообщества, поскольку там есть ссылки на другие сообщения с аналогичной настройкой, например: предотвращение внедрения sql, различия операторов и т. Д.   -  person Dave    schedule 28.06.2013
comment
@deceze: Если нет RTFM, никто не будет и RTFQA - существующие вопросы и ответы :)   -  person hakre    schedule 28.06.2013
comment
@hakre Да, на все это уже были даны ответы в тысячах отдельных случаев, поэтому найти их практически невозможно. Отсюда и это. Если у вас есть хорошие ответы, обязательно внесите их в ответ.   -  person deceze♦    schedule 28.06.2013
comment
@hakre Да, но каждый раз, когда я сталкиваюсь с вопросом, на который, как я знаю, отвечали тысячу раз, невозможно найти хорошую ссылку, против которой можно было бы закрыть глаза. Я не ожидаю, что люди просто найдут это себе, я хочу, чтобы он был точным ориентиром.   -  person deceze♦    schedule 28.06.2013
comment
@hakre Я понимаю, к чему вы клоните, но, думаю, ссылка на ошибку немного другая. Сортировка вам действительно нужно только один раз понять; Я думаю, что это лучше всего работает с одним последовательным ответом, объясняющим разные точки зрения. Разделение этого на отдельные ответы затруднило бы понимание ИМО каждого из них.   -  person deceze♦    schedule 28.06.2013
comment
@dat Это просто еще больше показывает, насколько необходима каноническая ссылка, если здесь уже есть несколько уровней вопросов. Если у вас есть конкретная идея по улучшению, которой вы хотите поделиться, вам следует обсудить ее на Meta.SO.   -  person deceze♦    schedule 06.05.2015


Ответы (13)


Базовые одномерные массивы

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

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

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

Разница между ними заключается только в том, сохраняются ли ассоциации "ключ-значение" (функции a), сортируются ли они по возрастанию или наоборот (r), сортируются ли значения или ключи (k) и как сравниваются значения (nat vs . обычный). См. 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($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);
}

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

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

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

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

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

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

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

Благодаря 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:

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);

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

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

Вы также можете сортировать более чем по одному столбцу в каждом направлении:

array_multisort(array_column($array, 'foo'), SORT_DESC,
                array_column($array, 'bar'), SORT_ASC,
                $array);

Начиная с PHP 7.0.0, вы также можете извлекать свойства из массива объектов.


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

person deceze♦    schedule 28.06.2013
comment
Функция числового сравнения не работает для значений с плавающей запятой; Я уверен, вы понимаете, о чем я :) - person Ja͢ck; 28.06.2013
comment
Для статического порядка я бы применил array_flip(), чтобы использовать более быстрый поиск позиции, например $order[$a['foo']] вместо array_search($a['foo'], $order). - person Ja͢ck; 29.06.2013
comment
Возможно, придется немного изменить: gist.github.com/Rizier123/24a6248758b53245a вы думаете, что это улучшение, и я включил все необходимое, что могу применить. - person Rizier123; 02.06.2016
comment
@ Rizier123 Я, конечно, аплодирую этим усилиям, это очень хорошая запись; но я бы предпочел, чтобы вы разместили его как отдельный ответ, даже если он очень похож. Ваш переписанный текст содержит много деталей (передача по ссылке, большая таблица и т. Д.), Но эта деталь отвлекает от плавного введения в основную тему работы функции сравнения, ИМХО. Я специально несколько раз обращаюсь к руководству специально, потому что именно там следует искать такие подробности; нет необходимости повторять это здесь и отвлекаться от основной идеи, которую я пытаюсь передать. - person deceze♦; 03.06.2016
comment
@deceze Основная проблема, поскольку это справочные вопросы и ответы, состоит в том, чтобы отображать информацию как можно более компактно и читабельно и упростить пользователям поиск своей функции сортировки. Я изменил несколько вещей: gist.github.com/Rizier123/24a6248758b532d63e подумайте об этом, если это полезно и ценно, публиковать его как отдельный ответ, так как это очень похожий контент - person Rizier123; 03.06.2016

Что ж, большинство основных методов уже охвачены обманом. Я бы попытался посмотреть на другие типы сортировки.

Сортировка с помощью 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);

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

Пузырьковая сортировка

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

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

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;
}

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

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

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

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;
}

Сортировка гребней

Из статьи в Википедии о гребенчатой ​​сортировке:

Комбинированная сортировка - это относительно простой алгоритм сортировки, первоначально разработанный Влодзимежем Добосевичем в 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;
}

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

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

В информатике сортировка слиянием (также обычно обозначаемая как сортировка слиянием) представляет собой алгоритм сортировки на основе сравнения 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;
}

Быстрая сортировка

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

Быстрая сортировка или сортировка с обменом разделами - это алгоритм сортировки, разработанный Тони Хоаром, который в среднем выполняет 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 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;
}
person Baba    schedule 28.06.2013
comment
@deceze, ты охватил все основы .. мне пришлось искать другой способ быть актуальным :) - person Baba; 28.06.2013
comment
Я не вижу ничего плохого в более академических методах сортировки :) намного менее полезны для большинства приложений, но иногда их могут попросить / потребовать, удобно иметь ссылку, тем более что со временем я забыл о большинстве из них - person Dave; 28.06.2013
comment
На самом деле, для быстрой сортировки рекомендуется выбирать сводную точку как медиану трех значений: первого, среднего и последнего элементов. Это мой пример выбора точки поворота. Это позволяет избежать наихудшего случая массива с обратной сортировкой (который вызывает O(n^2) сравнения, если мы будем использовать только первый элемент в качестве опорного) - person Alma Do; 04.05.2014
comment
Я слышал, что spl работают быстрее, чем обычная сортировка массивов. Верно? - person jewelhuq; 13.01.2016
comment
Я согласен с Дэйвом, в настоящее время почти всегда я включил это, почему я редко вспоминаю или использую его. - person Mike Nguyen; 10.03.2016
comment
@Baba PHP теперь предлагает деструктуризацию массива, которая позволяет пропускать временную переменную хранения во время пузырьковой сортировки. stackoverflow.com/a/60012548/2943403 - person mickmackusa; 04.02.2020

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

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

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

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

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

Результат такой:

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

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

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

Преобразование Шварца

Преобразование Шварца, также называемое идиомой «украсить-отсортировать-не декорировать», обеспечивает стабильную сортировку с по своей сути нестабильный алгоритм сортировки.

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

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]);
}));

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

person Ja͢ck    schedule 28.06.2013
comment
Ваша фраза влияет на стабильную сортировку с изначально нестабильным алгоритмом сортировки была для меня моментом ах-ха. На странице википедии нет упоминания слова «стабильный», что, как мне кажется, является достоинством преобразования. Стыд. - person Tyler Collier; 02.03.2015
comment
@TylerCollier Да, вам нужно читать между строк этой ссылки в Википедии ... Я избавил вас от этого ;-) - person Ja͢ck; 02.03.2015

Начиная с 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);
 }); 
person Orangepill    schedule 19.08.2013
comment
Просто помните, что это удалит любой предыдущий относительный порядок (например, первый июльский объект в предварительно отсортированном списке может оказаться в конце группы июльских объектов после сортировки). См. Стабильную сортировку выше. - person George Langley; 08.07.2014

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; } (может использоваться любой). Эти цепочки методов возвращают итераторы, итераторы можно преобразовать в массивы, добавив ->toArray() в конце, если необходимо.

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

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

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

person Athari    schedule 04.06.2015

Многомерная сортировка по ключевому значению

Естественная сортировка многомерного массива по значению ключа, а также сохранение исходного порядка (не перетасовывать основные ключи):

function multisortByKeyValue( $k, $arr ) {
    $ids   = array();
    $index = 1;

    foreach ( $arr as $key => $row ) {
        $ids[ $key ] = intval( $row[ $k ] ) . '-' . $index . '-' . $key;
        $index ++;
    }

    natsort( $ids );

    $arr = array_merge( $ids, $arr );

    return $arr;
}

Тестовый пример:

$arr = array(
    'id1' => array(
        'label'    => 'ID 1',
        'priority' => 30,
    ),
    'id2' => array(
        'label'    => 'ID 2',
        'priority' => 70,
    ),
    'id3' => array(
        'label'    => 'ID 3',
        'priority' => 20,
    ),
    'id4' => array(
        'label'    => 'ID 4',
        'priority' => 30,
    ),
);

$sorted = multisortByKeyValue( 'priority', $arr );

// $sorted equals to:
/*
array (
  'id3' => array (
    'label' => 'ID 3',
    'priority' => 20,
  ),
  'id1' => array (
    'label' => 'ID 1',
    'priority' => 30,
  ),
  'id4' => array (
    'label' => 'ID 4',
    'priority' => 30,
  ),
  'id2' => array (
    'label' => 'ID 2',
    'priority' => 70,
  ),
)
*/
person Andrew Surdu    schedule 30.01.2018

Очень удобно сортировать массивы с помощью sorted из 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]);
});

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

person Ihor Burlachenko    schedule 15.01.2016

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

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

производить

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )
person GAV    schedule 14.06.2019

Эта страница очень обширна, но я хочу добавить немного больше об удивительной полезности оператора космического корабля (оператора трехстороннего сравнения) - прекрасного потомка PHP7 +.

Использование оператора космического корабля для реализации нескольких условий сортировки

Это делает большие успехи в уменьшении раздувания кода и улучшении читаемости.

При написании собственной функции сортировки (_1 _ / _ 2 _ / _ 3_) для обработки нескольких условий вам нужно только написать сбалансированные массивы по обе стороны от оператора и вернуть результат. Больше никаких вложенных блоков условий или множественных возвратов.

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

Примеры данных для моих демонстраций:

$multidimArray = [
    'a' => [
        'boolean' => true,
        'natString' => 'text10',
        'object' => (object)['prop' => 2],
        'float' => -.5,
        'mixed' => []
    ],
    'b' => [
        'boolean' => true,
        'natString' => 'text12',
        'object' => (object)['prop' => 4],
        'float' => 0,
        'mixed' => null
    ],
    'c' => [
        'boolean' => false,
        'natString' => 'text100',
        'object' => (object)['prop' => 9],
        'float' => -.5,
        'mixed' => false
    ],
    'd' => [
        'boolean' => true,
        'natString' => 'text1',
        'object' => (object)['prop' => 9],
        'float' => -5,
        'mixed' => "\0"
    ],
    'e' => [
        'boolean' => false,
        'natString' => 'text2',
        'object' => (object)['prop' => 2],
        'float' => .5,
        'mixed' => ''
    ]
];

Демонстрации (чтобы избежать раздувания страницы Stackoverflow, см. демонстрационную ссылку для получения результатов):

  • Логика сортировки:

    1. boolean DESC (false = 0, true = 1, so trues before falses)
    2. плавающий ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
      
  • Логика сортировки:

    1. mixed ASC
    2. объект ASC
    3. логический ASC

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
      
  • Логика сортировки:

    1. property count of object ASC
    2. итерабельность смешанного DESC
    3. длина natString ASC
    4. natString ASC

      uasort($multidimArray, function($a, $b) {
          return [count(get_object_vars($a['object'])), is_iterable($a['mixed']), strlen($a['natString']), $a['natString']]
                 <=>
                 [count(get_object_vars($b['object'])), is_iterable($b['mixed']), strlen($b['natString']), $b['natString']];
      });
      

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

По вашему усмотрению, начиная с PHP7.4, вы можете использовать синтаксис стрелок с этими анонимными функциями. Тот же сценарий с синтаксисом стрелки.

person mickmackusa    schedule 04.12.2019

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

usort($arr, function($item, $nextItem) {
    return (max($nextItem->firstNumber, $nextItem->secondNumber)) - (max($item->firstNumber, $item->secondNumber));
});

Пример:

$foo = new stdClass;
$foo->createdDate = '10';
$foo->uploadedDate = '5';

$bar = new stdClass;
$bar->createdDate = '1';
$bar->uploadedDate = '12';

$baz = new stdClass;
$baz->createdDate = '25';
$baz->uploadedDate = '0';


$arr = [$foo, $bar, $baz];

// Order array by the highest number between "createdDate" and "uploadedDate".
usort($arr, function($item, $nextItem) {
    return (max($nextItem->createdDate, $nextItem->uploadedDate)) - (max($item->createdDate, $item->uploadedDate));
});

Результаты в:

array (
  0 => 
  (object) array(
     'createdDate' => '25',
     'uploadedDate' => '0',
  ),
  1 => 
  (object) array(
     'createdDate' => '1',
     'uploadedDate' => '12',
  ),
  2 => 
  (object) array(
     'createdDate' => '10',
     'uploadedDate' => '5',
  ),
)
person Lucas Bustamante    schedule 16.04.2021

Есть несколько способов отсортировать массив. Я упомяну некоторые методы для выполнения этой задачи. Прежде всего, я приведу целочисленный массив, который называется '$ numbers'.

$number = array(8,9,3,4,0,1,2);

Это нормальный способ создания массива. Предположим, я хочу отсортировать этот массив в порядке возрастания. Для этого можно использовать метод sort ().

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

Теперь рассмотрим результат этого,

введите здесь описание изображения

Вы можете видеть, что массив напечатанных чисел отсортирован. Если вы хотите, чтобы этот числовой массив сортировался в порядке убывания, для этой задачи можно использовать метод rsort ().

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

рассмотреть выход ..

введите здесь описание изображения

Теперь массив отсортирован в порядке убывания. Хорошо, давайте рассмотрим ассоциативный массив. Я дам ассоциативный массив (ассоциативный массив означает, что, массив, каждый индекс которого имеет уникальное значение ключа.), Как это,

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

Итак, теперь я хочу отсортировать этот массив в порядке возрастания в соответствии с их значением. Для этого можно использовать метод 'asort ()'.

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

Если сортировать по убыванию по их значению, можно использовать метод arsort (). Предположим, вы хотите отсортировать этот массив в соответствии с их значением ключа. В этом случае можно использовать метод ksort ().

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

Теперь рассмотрим результат. введите здесь описание изображения

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

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

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

Это некоторые методы сортировки массива в порядке возрастания или убывания в php. Надеюсь, вы уловили идею. Спасибо!

person GT_hash    schedule 26.08.2018
comment
Разве Deceze уже охватывает эти идеи: Разница между ними заключается только в том, сохраняются ли ассоциации "ключ-значение" (функции a), сортирует ли он по возрастанию или наоборот (r), сортирует ли значения или ключи (k) и как он сравнивает значения (естественные и нормальные). в принятом ответе? - person mickmackusa; 06.12.2019

Если кому-то нужно более простое решение для управления массивами, просто используйте пакет Laravel Collection, в котором есть реализованная функция sortBy, которая позволяет вам легко сортировать по ключам.

$collection->sortBy('forename')->sortBy('surname');

т.е. для сортировки сначала по a, затем по b, затем по c, правильным предложением будет

sortBy('c')->sortBy('b')->sortBy('a')

https://packagist.org/packages/tightenco/collect

person Rizerzero    schedule 05.03.2020

Самый простой - использовать функцию 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;
    });
person pihu    schedule 25.05.2016
comment
1) Пример и код несовместимы. 2) Это уже подробно описано в ответах выше. 3) Возможно, вы пытаетесь ответить на другой вопрос? - person deceze♦; 25.05.2016