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

How can I sort arrays and data in PHP?

提问人:deceze 提问时间:6/28/2013 最后编辑:Communitydeceze 更新时间:7/25/2022 访问量:94692

问:

这个问题旨在作为有关在 PHP 中对数组进行排序的问题的参考。很容易认为您的特定案例是独一无二的,值得提出新问题,但大多数实际上是本页解决方案之一的微小变化。

如果您的问题是作为本问题的重复而关闭的,请仅在您能解释为什么它与以下所有问题明显不同的情况下才要求重新打开您的问题。

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


  1. 基本一维数组;包括多维数组,包括对象数组;包括基于一个数组对另一个数组进行排序

  2. 使用 SPL 进行分拣

  3. 稳定排序

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

PHP 数组排序 对象 SPL

评论


答:

199赞 deceze 6/28/2013 #1

基本一维数组

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

适用的排序功能:

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

它们之间的区别仅仅在于是否保留了键值关联(“”函数),它是否从低到高排序或反向排序(“”),是否对值或键进行排序(“”)以及它如何比较值(“”与正常值)。有关概述和更多详细信息的链接,请参阅 http://php.net/manual/en/array.sorting.phparknat

多维数组,包括对象数组

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

如果要按每个条目的键“foo”进行排序,则需要自定义比较功能。上述函数和相关函数处理它们知道如何比较和排序的简单值。PHP不是简单地“知道”如何处理一个复杂的值,就像这样;所以你需要告诉它。$arraysortarray('foo' => 'bar', 'baz' => 42)

为此,您需要创建一个比较函数。该函数采用两个元素,如果这些元素被认为是相等的,则必须返回一个值,如果第一个值较低,则返回一个值,如果第一个值较高,则返回一个值。这就是所需要的:000

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将从数组中获取两个项目,并用它们调用您的函数。所以会被称为 as 和 as another .然后,该函数返回哪个值较大或它们是否相等。 重复此过程,为 和 传递不同的值,直到对数组进行排序。该函数将被调用多次,至少与 中的值一样多,每次都有不同的值组合。cmpcmp()$aarray('foo' => 'bar', 'baz' => 42)$barray('foo' => ..., 'baz' => ...)usortusort$a$bcmp$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)truesort($array);

自定义数值比较

如果要按键(数字)进行排序,则只需执行以下操作:baz

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

多亏了 PoWEr oF 数学,这返回一个值 0、0 或 0 <>,具体取决于是低于、等于还是大于 。$a$b

请注意,这不适用于值,因为它们会减少到 an 并失去精度。请改用显式 和 return 值。floatint-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'];
}

按多个字段排序

如果要主要按 排序,但如果两个元素相等,则排序为 :foofoobaz

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

按手动静态顺序进行分类

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


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

评论

0赞 Ja͢ck 6/28/2013
数值比较函数不适用于浮点值;我相信你明白我的意思:)
2赞 Ja͢ck 6/29/2013
对于静态订单,我会申请使用更快的位置查找,例如 而不是。array_flip()$order[$a['foo']]array_search($a['foo'], $order)
0赞 Rizier123 6/3/2016
可能有点大的编辑:gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b 但如果你认为这是一个改进,并且我包含了所有必要的内容,我可以应用它。
0赞 deceze 6/3/2016
@Rizier123我当然为这种努力鼓掌,这是一篇非常好的文章;但如果你把它作为单独的答案发布,我宁愿它,即使它非常相似。您的重写包含很多细节(通过引用、大表等),但这些细节分散了对比较函数工作核心主题的顺利介绍,恕我直言。我特意多次明确地参考了手册,因为这是应该查找这些细节的地方;没有必要在这里重复它,分散我试图传达的核心思想的注意力。
0赞 Rizier123 6/3/2016
@deceze 由于它是一个参考问答,主要的挑战是尽可能紧凑和可读地显示信息,并使用户易于找到他们的排序功能。我调整了几件事: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b 但我仍然必须考虑一下,如果将其作为单独的答案发布有用且有价值,因为它的内容非常相似
143赞 Baba 6/28/2013 #2

好吧,大多数基本方法已经被欺骗所涵盖,我会尝试查看其他类型的分类

使用 SPL 进行分拣

SplHeap

class SimpleHeapSort extends SplHeap {
    public function compare($a, $b) {
        return strcmp($a, $b);
    }
}

// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");

echo implode(PHP_EOL, iterator_to_array($heap));

输出

c
b
a

SplMaxHeap

SplMaxHeap 类提供堆的主要功能,将最大值保持在顶部。

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

SplMinHeap

SplMinHeap 类提供堆的主要功能,将最小值保留在顶部。

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

其他类型的排序

气泡排序

摘自维基百科上关于气泡排序的文章:

气泡排序,有时被错误地称为下沉排序,是一种简单的排序算法,其工作原理是重复单步执行要排序的列表,比较每对相邻项目,如果它们的顺序错误,则交换它们。重复传递列表,直到不需要交换,这表示列表已排序。该算法的名称来源于较小元素“气泡”到列表顶部的方式。因为它只使用比较来操作元素,所以它是一种比较排序。尽管该算法很简单,但大多数其他排序算法对于大型列表更有效。

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,也称为 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 年设计。后来,斯蒂芬·莱西(Stephen Lacey)和理查德·博克斯(Richard Box)于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 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赞 Baba 6/28/2013
@deceze你涵盖了所有的基础知识......我不得不寻找另一种方式来与:)
5赞 Dave 6/28/2013
我看不出更学术的排序方法有什么问题:)对于大多数应用程序来说,用处要小得多,但偶尔它们可能会被要求/需要,这很方便,可以参考,特别是因为随着时间的推移,我已经忘记了其中的大部分
0赞 Alma Do 5/4/2014
实际上,为了快速排序,建议选择枢轴作为三个值的中位数:第一个、中间和最后一个元素这是我的枢轴选择示例。这样可以避免最坏情况下的反向排序数组(如果我们只使用第一个元素作为枢轴,这会导致比较)O(n^2)
0赞 jewelhuq 1/13/2016
我听说 spl 的工作速度比普通数组排序快。这是对的吗?
0赞 Mike Nguyen 3/10/2016
我同意戴夫的观点,现在,几乎已经包括了我很少记得或使用它的原因。
44赞 Ja͢ck 6/28/2013 #3

稳定排序

假设你有一个这样的数组:

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

现在你只想对第一个字母进行排序:

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

结果是这样的:

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

排序不稳定!

敏锐的观察者可能已经注意到,数组排序算法 (QuickSort) 没有产生稳定的结果,并且没有保留相同首字母单词之间的原始顺序。这种情况是微不足道的,我们应该比较整个字符串,但让我们假设你的用例更复杂,例如对不同字段进行两次连续排序,这不应该抵消彼此的工作。

施瓦茨变换

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

瞧!您的原始比较代码又回来了。

评论

0赞 Tyler Collier 3/2/2015
你的那句话“用固有的不稳定的排序算法影响稳定的排序”对我来说是啊哈时刻。维基百科页面没有提到稳定这个词,在我看来,这似乎是转换的美妙之处。羞耻。
1赞 Ja͢ck 3/2/2015
@TylerCollier是的,您需要阅读维基百科参考资料的字里行间......我省去了你这样做的麻烦;-)
16赞 Orangepill 8/20/2013 #4

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

评论

0赞 George Langley 7/9/2014
请记住,这将删除任何先前的相对顺序(例如,预排序列表中的第一个“July”对象可能在排序后的 July 对象组的末尾结束)。请参阅上面的“稳定排序”。
10赞 Athari 6/4/2015 #5

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

这里,是(两者都可以使用)的简写。这些方法链返回迭代器,如果需要,可以通过添加 end 来将迭代器转换为数组。'$v->count'function ($v) { return $v->count; }->toArray()

在内部,相关方法调用适当的数组排序函数(、、等)。orderByuasortkrsortmultisortusort

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

* 由我开发,有关更多详细信息以及与其他 LINQ 端口的比较,请参阅自述文件

2赞 Ihor Burlachenko 1/16/2016 #6

使用 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赞 pihu 5/25/2016 #7

最简单的方法是使用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;
    });

评论

1赞 deceze 5/25/2016
1)示例和代码不一致。2)这在上面的答案中已经进行了非常详细的解释。3) 您是否可能试图回答不同的问题?
3赞 Andrei Surdu 1/31/2018 #8

按键值进行多维排序

按键值对多维数组进行自然排序,并保持原始顺序(不要洗牌主键):

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,
  ),
)
*/
-1赞 Gayan Sampath 8/26/2018 #9

有几种方法可以对数组进行排序。我将提到一些执行该任务的方法,我将给出一个称为“$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."  ";
   }
?>

现在考虑它的输出,

enter image description here

您可以看到打印的数字数组已排序。如果您希望该数字数组按降序排序,则可以将“rsort()”方法用于该任务。

<?php

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

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

考虑输出。.

enter image description here

现在数组按降序排序。好的,让我们考虑一个关联数组。我将给出一个关联数组(关联数组意味着,每个索引都有唯一键值的数组。

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

所以,现在我想根据它们的值按升序对这个数组进行排序。

<?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."  ";
     }
?>

现在考虑输出。enter image description here

现在数组根据它们的键值进行排序。如果要根据数组的键值按降序对数组进行排序,可以使用'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."  ";
    }
?>

现在,关联数组根据其键值按降序排序。查看输出。enter image description here

这些是在 php 中按升序或降序对数组进行排序的一些方法。我希望你能得到一个想法。谢谢!

评论

0赞 mickmackusa 12/6/2019
Deceze 不是已经涵盖了这些见解吗:“它们之间的区别仅仅在于是否保留了键值关联(”a“函数),它是否从低到高排序或反向排序(”r“),它是否对值或键进行排序(”k“)以及它如何比较值(”nat“与正常)”?
2赞 GAV 6/15/2019 #10

如果你想按键值排序,那么你可以做一行,优雅而清晰。这将按价格升序排序。使用 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 ) )
3赞 mickmackusa 12/4/2019 #11

这个页面非常全面,但我想补充一点关于宇宙飞船操作员(三向比较操作员)的令人敬畏的实用程序 - 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,所以 true 在 false 之前)
    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工具带中......当你在处理非数据库数据时,因为SQL当然会是一种更明智的技术。

根据您的判断,从 PHP7.4 开始,您可以将箭头语法与这些匿名函数一起使用。具有箭头语法的相同脚本

-1赞 Rizerzero 3/6/2020 #12

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

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

即,为了先按 a 排序,然后按 b,然后按 c 排序,正确的子句是

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

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

0赞 Lucas Bustamante 4/17/2021 #13

如果要根据基于多个条件的绝对最高值对数组进行排序,这里有一个简单的方法:

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',
  ),
)
-1赞 Bilbo 7/25/2022 #14

这个答案是关于多列排序的,其中数组应该按每个一维元素中非连续索引的值进行排序。 这与多维排序不同,因为每个元素仅由各种 Key=>Value 对组成。

function fncCmp( array $ItmOne, array $ItmTwo ) {       ; # callback for sorting items (which are arrays) by values at specific indexes
  $strCmpOne = $ItmOne[ 'ColOne' ] . $ItmOne[ 'ColThr' ]; # build compound values
  $strCmpTwo = $ItmTwo[ 'ColOne' ] . $ItmTwo[ 'ColThr' ]; #   to compare
  return $strCmpOne <=> $strCmpTwo                      ; # pass back comparison-result
} # fncCmp

$arrDat = array(                                                       # define an array of items
  array( 'ColOne' => 'Val2', 'ColTwo' => 'Val8', 'ColThr' => 'Val6' )  #   each of which
 ,array( 'ColOne' => 'Val2', 'ColTwo' => 'Val9', 'ColThr' => 'Val4' )  #   is an
 ,array( 'ColOne' => 'Val1', 'ColTwo' => 'Val7', 'ColThr' => 'Val5' )  #   array of
)                                                                    ; #   fields
var_dump       ( $arrDat           )                                 ; # emit items before sort
$bolSrt = usort( $arrDat, 'fncCmp' )                                 ; # sort the array by comparing elements
var_dump       ( $arrDat           )                                 ; # emit items after  sort