如何在PHP中对数组和数据进行排序?

324

此问题旨在提供关于PHP数组排序的问题的参考。您可能认为您的特殊情况是独一无二的,并值得一个新问题,但大多数实际上只是本页解决方案的轻微变体。

如果您的问题被关闭并作为重复问题,请仅在您能够解释它与下面所有问题都有显著不同之处时,请请求重新打开您的问题。

如何在PHP中对数组进行排序?
如何对复杂数组进行排序?
如何对对象数组进行排序?


  1. 基本一维数组;包括多维数组、包括对象数组;包括基于另一个数组的排序

  2. 使用SPL进行排序

  3. 稳定的排序

对于使用PHP现有函数的实用答案,请参见1.;对于排序算法的学术详细答案(PHP的函数实现和您可能需要应对真正复杂的情况),请参见2。

14个回答

199

基本的一维数组

$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' => ...),
    ...
);

如果你想按照每个条目中键名为'foo'的值对$array进行排序,则需要一个自定义比较函数。上述的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' => ..., 'baz' => ...)作为$b。然后该函数返回到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'];
}

感谢数学的力量,这将根据$a小于、等于或大于$b而返回小于0、0或大于0的值。

请注意,对于浮点数,这种方法可能不太适用,因为它们会被转换为整数并且会失去精度。建议改为使用显式的-101返回值。

对象

如果你有一个对象数组,它的运作方式与上述相同:

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的期望行为,它返回-101

太空船运算符

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 版本起,您也可以从对象数组中提取属性。


如果您有更常见的情况,请随时编辑此答案。


数字比较函数不适用于浮点数值;我相信你知道我的意思 :) - Ja͢ck
2
对于静态顺序,我会应用 array_flip() 来利用更快的位置查找,例如 $order[$a['foo']] 而不是 array_search($a['foo'], $order) - Ja͢ck
可能需要进行一些较大的编辑:https://gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b 但如果您认为这是一个改进,而且我已经包含了所有必要的内容,我可以应用它。 - Rizier123
@Rizier123,我当然赞赏你的努力,这是一篇非常好的文章;但是我更希望你将其发布为单独的答案,即使它非常相似。你的改写包含了很多细节(按引用传递、大表格等),但是这些细节会分散读者对比较函数工作原理核心主题的注意力,我的意见是如此。我有意多次明确地参考手册,因为这些细节应该在那里查找;没有必要在这里重复并分散我试图传达的核心思想。 - deceze
@deceze 主要的挑战,因为这是一个参考问答,是尽可能紧凑和易读地显示信息,并使用户轻松找到他们的排序功能。我调整了一些东西:https://gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b 但我仍然需要考虑一下,是否有用和有价值将其发布为单独的答案,因为它是非常相似的内容。 - Rizier123
array_multisort() 对我没有起作用;请参见下面的更简单的答案 - Bilbo

143

我会尽力查看其他类型的排序方法,因为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);

其他类型的排序

冒泡排序

来自维基百科关于冒泡排序的文章:

冒泡排序,有时被错误地称为沉降排序,是一种简单的排序算法,通过重复遍历要排序的列表,比较每对相邻项并交换它们(如果它们的顺序不正确)。对列表的遍历重复进行,直到不需要交换为止,这表明列表已排序。该算法得名于较小的元素“冒泡”到列表的顶部的方式。由于它只使用比较来操作元素,因此它是一种比较排序。虽然该算法很简单,但对于大型列表来说,大多数其他排序算法更有效率。

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

希尔排序

来自维基百科关于希尔排序的文章:

希尔排序,也称为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年被Stephen Lacey和Richard Box重新发现。梳排序改进了冒泡排序。

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开发的一种排序算法,平均情况下,它需要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 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,你已经涵盖了所有基础知识.. 我得寻找其他方法来保持相关性 :) - Baba
5
我认为更加学术的分类方法没有任何问题 :) 对于大多数应用而言它们不太有用,但偶尔可能会被要求使用,因此拥有一个参考资料会很方便,尤其是随着时间的推移,我已经忘记了其中的大部分。 - Dave
实际上,对于快速排序,建议选择中位数作为枢轴:第一个元素、中间元素和最后一个元素。这是我的枢轴选择示例。这样可以避免最坏情况下的逆序数组(如果我们只使用第一个元素作为枢轴,则会导致O(n^2)比较)。 - Alma Do
我听说 SPL 比普通数组排序更快,这是正确的吗? - jewelhuq
我同意Dave的观点,现在几乎所有的前端框架都已经包含了这个功能,所以我很少会去记住或使用它。 - Mike Nguyen
@Baba PHP现在提供了“数组解构”,可以在冒泡排序时省略临时变量的使用。https://stackoverflow.com/a/60012548/2943403 - mickmackusa

44

稳定排序

假设你有这样一个数组:

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

现在您只想按第一个字母排序:

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

结果是这样的:

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

排序不稳定!

仔细观察者可能会注意到,数组排序算法(快排)未产生稳定的结果,同一首字母的单词之间的原始顺序未得到保留。 这种情况是微不足道的,我们本应该比较整个字符串,但让我们假设您的用例更加复杂,例如在不同字段上进行两次连续排序,它们不应该抵消对方的工作。

Schwartzian变换

Schwartzian变换,也称为装饰-排序-去除装饰惯用语,以内在不稳定的排序算法实现稳定排序。

首先,您需要使用另一个数组对每个数组元素进行装饰,其中包括一个主键(值)和一个次要键(其索引或位置):

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

看呐!你的原始比较代码又回来了。


你的短语“使用本质上不稳定的排序算法实现稳定排序”让我恍然大悟。维基百科页面中没有提到“稳定”这个词,而这似乎正是这种转换的美妙之处。可惜了。 - Tyler Collier
1
@TylerCollier 是的,你需要在那个维基百科参考资料中看出更多的东西...我已经为你省去了这个麻烦;-) - Ja͢ck

16

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

请记住,这将删除任何先前的相对顺序(例如,在预排序列表中的第一个“July”对象可能在排序后出现在July对象组的末尾)。请参见上面的“稳定排序”。 - George Langley

10

LINQ

在.NET中,LINQ经常用于排序,相比较于比较函数,特别是需要按多个字段进行排序时,它提供了更好的语法形式。有几个针对PHP的LINQ移植库,其中包括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 和相关方法调用适当的数组排序函数(uasortkrsortmultisortusort 等)。

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

* 由我开发,有关更多详细信息以及与其他 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,
  ),
)
*/

3

这个页面非常全面,但我想多加一点关于太空船运算符(三路比较运算符)的强大实用性——它是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页面膨胀,请参见演示链接以查看输出):
  • Sorting logic:

    1. boolean DESC (false = 0, true = 1, so trues before falses)
    2. float ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
      
  • Sorting logic:

    1. mixed ASC
    2. object ASC
    3. boolean ASC

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
      
  • Sorting logic:

    1. property count of object ASC
    2. iterability of mixed DESC
    3. natString length 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起,您可以自行决定是否使用箭头语法来编写这些匿名函数。 使用箭头语法的相同脚本

2
使用Nspl中的sorted函数对数组进行排序非常方便:

基本排序

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

0
如果你想根据多个条件中的绝对最高值对数组进行排序,这里有一个简单的方法:
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',
  ),
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接