这个问题旨在作为PHP中关于数组排序的问题的参考。很容易认为您的特定情况是独特的,值得提出一个新问题,但大多数情况实际上是本页上某个解决方案的微小变化。 如果你的问题是这个问题的副本,请要求重新打开你的问题,只有当你能解释为什么它与下面所有的问题都有显著不同时。

我如何排序一个数组在PHP? 我如何排序一个复杂的数组在PHP? 如何在PHP中排序对象数组?


基本一维数组;包括多维数组,包括对象数组;包括根据一个数组对另一个数组排序 用SPL排序 稳定的排序

使用PHP现有函数的实际答案见1。,关于排序算法的学术详细答案(PHP函数实现,在非常非常复杂的情况下可能需要它),请参见2。


当前回答

如果有人想要一个更简单的解决方案来操作数组,只需使用Laravel Collection包,它有一个实现的sortBy函数,可以让你简单地按键排序。

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

也就是说,为了先按a,然后按b,然后按c排序,正确的子句应该是

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

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

其他回答

基本一维数组

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

适用的排序函数:

排序 函数 带点 arsort 的作用 natcasesort ksort 作用

它们之间的区别仅仅在于是否保留键值关联(“a”函数),是从低到高排序还是反向排序(“r”),是对值排序还是对键排序(“k”),以及如何比较值(“nat”vs. normal)。有关概述和进一步细节的链接,请参阅http://php.net/manual/en/array.sorting.php。

多维数组,包括对象数组

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

如果你想根据每个条目的'foo'键对$array排序,你需要一个自定义比较函数。上面的排序和相关函数工作在简单的值上,它们知道如何比较和排序。PHP并不简单地“知道”如何处理复杂的值,例如数组('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 will take two items from the array and call your cmp function with them. So cmp() will be called with $a as array('foo' => 'bar', 'baz' => 42) and $b as another array('foo' => ..., 'baz' => ...). The function then returns to usort which of the values was larger or whether they were equal. usort repeats this process passing different values for $a and $b until the array is sorted. The cmp function will be called many times, at least as many times as there are values in $array, with different combinations of values for $a and $b every time.

要习惯这个想法,试试这个:

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,而不是一个排序的数组。只是数组($);的工作原理。

自定义数值比较

如果你想按baz键排序,它是数字,你所需要做的就是:

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

感谢MATH的力量,这将返回一个< 0,0或> 0的值,取决于$a是否小于、等于或大于$b。

注意,这对于浮点值并不适用,因为它们将被简化为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'];
    }
}

对于那些熟悉的人来说,这相当于一个带有ORDER BY foo, baz的SQL查询。 还可以查看这个非常简洁的简写版本,以及如何为任意数量的键动态创建这样的比较函数。

按手动、静态顺序排序

如果你想将元素按“手动顺序”排序,比如“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开始,您还可以从对象数组中提取属性。


如果你有更多的常见情况,请随意编辑这个答案。

大多数基本的方法都已经讲过了,我会试着看看其他类型的排序

用SPL排序

碎片堆

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, sometimes incorrectly referred to as sinking sort, is a simple sorting algorithm that works by repeatedly stepping through the list to be sorted, comparing each pair of adjacent items and swapping them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted. The algorithm gets its name from the way smaller elements "bubble" to the top of the list. Because it only uses comparisons to operate on elements, it is a comparison sort. Although the algorithm is simple, most of the other sorting algorithms are more efficient for large lists.

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

插入排序

来自维基百科关于插入排序的文章:

插入排序是一种简单的排序算法,每次构建一个最终排序的数组(或列表)。在大型列表上,它的效率远远低于更高级的算法,如快速排序、堆排序或归并排序。然而,插入排序提供了几个优点:

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

梳子排序

摘自维基百科关于梳状排序的文章:

梳状排序是由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;
}

去排序

摘自维基百科关于归并排序的文章:

在计算机科学中,归并排序(也通常拼写为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;
}

快速排序

维基百科上关于快速排序的文章:

快速排序,或分区交换排序,是由Tony Hoare开发的一种排序算法,平均而言,对n个项目进行O(n log 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排序的文章:

在计算机科学中,基数排序是一种非比较整数排序算法,它通过将键按具有相同重要位置和值的单个数字分组,对具有整数键的数据进行排序。

// 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_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 ) )

LINQ

在. net中,LINQ经常用于排序,它提供了比比较函数更好的语法,特别是当对象需要按多个字段排序时。LINQ到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'是函数($v) {return $v->count;}(任何一个都可以使用)。这些方法链返回迭代器,迭代器可以通过在最后添加->toArray()转换为数组。

在内部,orderBy和相关方法调用适当的数组排序函数(uasort、krsort、multisort、usort等)。

LINQ包含了更多受SQL启发的方法:过滤、分组、连接、聚合等。它最适合在不依赖数据库的情况下执行对数组和对象的复杂转换。

*由我开发,请参阅自述文件以了解更多细节和与其他LINQ端口的比较

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