如何在PHP中对数组和数据进行排序?基本一维数组多维数组,包括对象数组根据一个数组对另一个数组进行排序使用 SPL 进行排序

2022-08-30 06:03:37

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

如果您的问题作为此问题的副本而关闭,请仅在您能够解释为什么它与以下所有内容明显不同时才要求重新打开您的问题。

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


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

  2. 使用 SPL 进行排序

  3. 稳定排序

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


答案 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 另一个 .然后,该函数返回到哪个值较大或它们是否相等。 重复此过程,为数组传递不同的值,直到对数组进行排序。该函数将被调用多次,至少与 中的值一样多次调用,并且每次都有不同的值组合。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 MATH,它返回一个值<0,0或>0,具体取决于是否小于,等于或大于。$a$b

请注意,这不适用于值,因为它们将被简化为 a 并失去精度。请改用显式 和返回值。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'];
    }
}

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

按手动静态顺序分类

如果要将元素排序为“手动顺序”,如“foo”,“bar”,“baz”

function cmp(array $a, array $b) {
    static $order = array('foo', 'bar', 'baz');
    return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

对于上述所有内容,如果您使用的是 PHP 5.3 或更高版本(您确实应该这样做),请使用匿名函数来编写较短的代码,并避免有另一个全局函数浮动:

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

这就是对复杂的多维数组进行排序的简单程度。同样,只要想想教PHP如何分辨两个项目中哪一个是“更大”的;让PHP进行实际的排序。

同样对于上述所有内容,要在升序和降序之间切换,只需交换和参数即可。例如:$a$b

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

根据一个数组对另一个数组进行排序

然后是一个特殊的array_multisort,它允许您根据一个数组对另一个数组进行排序:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

此处的预期结果将是:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

用于到达那里:array_multisort

array_multisort($array1, $array2);

从 PHP 5.5.0 开始,您可以使用从多维数组中提取列,并对该列上的数组进行排序:array_column

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

您还可以在任一方向上对多个列进行排序:

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

从 PHP 7.0.0 开始,您还可以从对象数组中提取属性。


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


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

快速排序

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

Quicksort或分区交换排序是由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排序的文章:

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

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