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

由于“我如何对我独特的阵列雪花进行分类?”这样庞大而重复的数量? 问题,这是PHP中基本排序方法的参考集合。 请关闭任何与本文无重复区别的问题。

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


  • 基本的一维数组; 含。 多维数组,包括 对象数组; 含。 基于另一个排序一个数组

  • 用SPL排序

  • 稳定的排序

  • 有关使用PHP现有函数的实际答案,请参阅1.有关排序算法的学术详细答案(PHP的函数实现以及您可能需要的是真正复杂的案例),请参阅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的文章:

    壳牌,也被称为壳牌排序或壳牌的方法,是一种就地比较排序。 它通过开始比较和交换具有相距很远的元素的元素进行比较和交换,然后再完成相邻元素的交换,从而推广一种交换排序,例如插入或冒泡排序。

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

    快速排序

    从维基百科关于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 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 = 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)这样的复杂值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
  • uasort
  • uksort
  • 同样,它们只是在保持键值关联和按值或键排序方面有所不同。 详情请阅读他们的文档。

    用法示例:

    usort($array, 'cmp');
    

    usort将从数组中取两个项目并与他们一起调用你的cmp函数。 所以cmp()将以$a作为array('foo' => 'bar', 'baz' => 42)调用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'];
    }
    

    由于数学运算的原因,这取决于$a是小于,等于还是大于$b ,返回一个<0,0或> 0的值。

    请注意,这将不适用于float值,因为它们会减少到一个int并失去精度。 使用明确的-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);
    

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


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


    稳定的排序

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

    ['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变换也被称为装饰分类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]);
    }));
    

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

    链接地址: http://www.djcxy.com/p/57583.html

    上一篇: How can I sort arrays and data in PHP?

    下一篇: PHP practical advantages for using echo over print