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

292

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

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

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


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

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

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

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

децезе
источник
@jterry Точно, именно поэтому я сделал это, чтобы наконец иметь хороший вопрос для обсуждения Ответ на каждую уникальную снежинку индивидуально никому не поможет. :)
deceze
3
Я думаю, что люди должны просто взглянуть на php.net
Александр Жардим
@ Алекс Ха! Абсолютно. Проблема в том, что никто не RTFM. : D
deceze
2
У нас уже есть эти ответы, я предлагаю вам перечислить лучшие ответы внутри каждого ответа здесь вместо того, чтобы дублировать (или переписывать) контент. Кроме того, массивы, как правило, можно рассматривать по отдельности, поэтому в любом случае работа по-прежнему близка к голосованию против дураков.
Хакре
1
@deceze: Если никто не RTFM, никто не будет также RTFQA - существующие вопросы и ответы :)
hakre

Ответы:

164

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

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

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

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

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

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


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

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

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

Сортировка с 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 Sort:

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

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

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

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

В информатике сортировка слиянием (также обычно пишется как mergesort) является алгоритмом сортировки, основанным на сравнении (O 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

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

Быстрая сортировка, или сортировка по разделу, - это алгоритм сортировки, разработанный Тони Хоаром, который в среднем выполняет 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;
}
ромовая баба
источник
4
@ deceze вы охватили все основы .. мне пришлось искать другой способ быть актуальным :)
Баба
5
Я не вижу ничего плохого в более академических методах сортировки :), которые не так полезны для большинства приложений, но иногда их могут попросить / потребовать, полезно иметь ссылку, тем более, что я со временем забыл о большинстве из них
Дейв
На самом деле, для быстрой сортировки рекомендуется выбрать сводку как медиану трех значений: первый, средний и последний элементы . Это мой пример выбора опорных точек. Это позволяет избежать массива с обратной сортировкой в ​​худшем случае (который вызывает O(n^2)сравнение, если мы будем использовать только первый элемент в качестве сводного)
Alma Do
Я слышал, что spl работает быстрее, чем обычная сортировка массивов. Это правильно?
jewelhuq
Я согласен с Дейвом, в настоящее время почти fw включил это, почему я редко помню или использую это.
Майк Нгуен
43

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

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

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

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

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

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

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

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

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

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

Преобразование Шварца , также называемое идиомой decorate-sort-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]);
}));

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

Разъем
источник
Ваша фраза «производит стабильную сортировку с помощью нестабильного алгоритма сортировки» была для меня моментом ах-ха. На странице википедии нет упоминания слова «стабильный», которое мне кажется прелестью преобразования. Позор.
Тайлер Кольер
1
@TylerCollier Да, вам нужно читать между строк этой ссылки на Википедию ... Я избавил вас от необходимости делать это ;-)
Ja͢ck
15

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

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

 $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);
 }); 
Orangepill
источник
Просто помните, что это удалит любой предыдущий относительный порядок (например, первый объект «Июль» в предварительно отсортированном списке может оказаться в конце группы объектов июля после сортировки). Смотрите «Стабильная сортировка» выше.
Джордж Лэнгли
9

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

Асария
источник
3

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

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

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,
  ),
)
*/
Эндрю Сурду
источник
2

Сортировать массивы с помощью отсортированной функции из 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]);
});

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

Игорь Бурлаченко
источник
2

Если вы хотите заказать по значению ключа, то вы можете сделать это одной строкой, элегантно и понятно. Это будет порядок по возрастанию цены. Использует 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 ) )
GAV
источник
1

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

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

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

При написании пользовательской функции сортировки ( usort()/ uasort()/ uksort()) для обработки нескольких условий вам нужно только написать сбалансированные массивы по обе стороны от оператора и вернуть результат. Нет больше вложенных блоков условий или множественных возвратов.

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

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

$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. логическое DESC (false = 0, true = 1, поэтому верно перед ложными значениями)
    2. плавать ASC

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

    1. смешанный 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. количество свойств объекта 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 toolbelt ... для случаев, когда вы обрабатываете данные не из базы данных - потому что, конечно, SQL был бы гораздо более разумным методом.

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

mickmackusa
источник
0

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

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

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

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

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

Rizerzero
источник
-1

Существует несколько способов сортировки массива. Я упомяну некоторые методы для выполнения этой задачи. Из всех я приведу целочисленный массив, который называется «$ 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. Я надеюсь, что вы могли бы получить представление. Спасибо!

GT_hash
источник
Разве Deceze уже не покрывает эти идеи следующим образом: «Разница между ними заключается лишь в том, сохраняются ли ассоциации ключ-значение (функции« a »), сортирует ли она от низкого к высокому или обратное (« r »), независимо от того, сортирует значения или ключи («k») и сравнивает значения («nat» и «normal»). " в принятом ответе?
mickmackusa
-2

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