4.2数组排序
PHP中的数组实际上是一个有序映射。无论是队列、数组、堆栈还是字典,用PHP编程时都可以统一使用PHP的数组类型。在这一节中,我们只讨论PHP数组的排序,因为数组的排序会被很多项目使用。虽然数据库也可以方便的排序,但是在复杂动态的业务规则下,需要在PHP代码层进行处理。因此,加深对PHP数组的理解将有利于项目开发。
4.2.1一个面试问题引发的思考
在我现在的公司,有一个关于数组排序的面试问题。简化提炼一下,题目是:
请根据以下规则对专辑中的歌曲进行排序。
1。根据播放次数,从高到低排序。
2。如果播放次数相同,则按收***数排序。
3。如果收藏者数量相同,则按下载数量排序。
并且假设有如下的专辑歌曲列表:
表4-1歌曲列表
通常,这个问题有三种答案。
第一种是一开始就一头扎进大学时代的排序算法。想着从头到尾重新实现一套冒泡排序算法,或者快速排序。如果能达到最好的性能也是个好主意,而且能准确快速的实现。然而,这更多的是理论上的。在实际业务需求的开发中,很少需要重新实现通用排序算法。相反,我们只需要能够使用它。
所以第二种答案是用最少的代码快速实现业务需求。无论是使用打包的第三方开源类库,还是PHP原生态提供的数组排序功能,只要能实现以上排序规则即可。在这种情况下,可以使用array_multisort()函数。这个排序函数很强大,所以理解起来会有点困难。根据官方文档,array_multisort()可以用来一次性对多个数组进行排序,也可以按照一维或多维对多维数组进行排序。
例如,在这里,它可以这样实现:
<?php// 示例数据$songs = array( array('title' => '恰似你的温柔', 'play' => 1000, 'like' => 900, 'download' => 800), array('title' => '丁香花', 'play' => 2000, 'like' => 700, 'download' => 500), array('title' => '突然的自我', 'play' => 2000, 'like' => 800, 'download' => 1300), array('title' => '夜空中最亮的星', 'play' => 800, 'like' => 1000, 'download' => 700),);// 初始化辅助数据$playTimes = $likeTimes = $downloadTimes = array();foreach ($songs as $it) { $playTimes[] = $it['play']; $likeTimes[] = $it['like']; $downloadTimes[] = $it['download'];}// 用一行代码,根据多维对多维数组进行排序array_multisort( $playTimes, SORT_DESC, SORT_NUMERIC, // 排序规则1 $likeTimes, SORT_DESC, SORT_NUMERIC, // 排序规则2 $downloadTimes, SORT_DESC, SORT_NUMERIC, // 排序规则3 $songs);print_r($songs);
最后,通过运行上面的代码,您可以看到结果输出是:
Array( [0] => Array ( [title] => 突然的自我 [play] => 2000 [like] => 800 [download] => 1300 ) [1] => Array ( [title] => 丁香花 …… ) [2] => Array ( [title] => 恰似你的温柔 …… ) [3] => Array ( [title] => 夜空中最亮的星 …… ))
除了前面的样本数据之外,上述三个规则的排序,只需要中间循环一次初始化辅助数据就可以方便地实现。但是这不是最佳的。我们来看第三类答案。
在揭晓第三种答案之前,先简单回顾一下我们在中学是如何解二次(或高次)方程的。例如,这个等式:
很简单。我们先简化,再求解。也就是说,它被简化为我们熟悉的一维线性方程:
求两边的平方根得到:
所以,最后的答案是x=3或者x=-1。那不是很容易吗?
同理,如果我们对三维排序不熟悉,或者无法入门,那么如果只是一维数组排序呢?可以简单处理吗?
这就是我们所说的第三种答案——最简单的解决方案。这也被称为降维。有了新的思路,再解决就不难了。关键是,我们需要找到一个独特的映射,使:
然后根据这个映射规则,将三维比较化简为一维比较,最后数组排序也能达到同样的效果。以下是针对当前示例数据的参考实现。
<?php// 三维降一维$points = array();foreach ($songs as $it) { $points[] = 1000000 * $it['play'] + 1000 * $it['like'] + $it['download'];}// 再排序array_multisort($points, SORT_DESC, SORT_NUMERIC, $songs);
4.2.2数组排序的理解
关于PHP数组的排序函数有好几个,但是通常开发的同学只记得sort()和ksort(),其他很多排序函数都记不住,或者没有什么印象。下面介绍如何快速记住这些排序函数。
从官方文档中提取,用于排序数组的函数有:
array_multisort()asort()arsort()krsort()ksort()natcasesort()natsort()rsort()shuffle()sort()uasort()uksort()usort()
全部列出来,有13个之多。那你是怎么记住的?其实在科学上,每个人都是有技术的,靠的是理解,而不是死记硬背。就像数学公式一样,要学会灵活运用。
众所周知,PHP数组由键和值组成,排序顺序可以是升序也可以是降序。根据这两个维度,我们可以对以上13个排序函数进行分类。首先分为两类:排序值和排序键。如下表所示。
表4-2数组排序函数
递升序列
降序
定制
自然分类
其他的
排序值
sort()、asort()
rsort()、arsort()
usort()、uasort()
natsort()、natcasesort()
shuffle()、array_multisort()
排序关键字
ksort()
krsort()
uksort()
这个分类明确之后,我们再来看看如何记住这个结函数的名字。可以发现,除了名为shuffle()的随机排序函数外,所有排序函数都以“sort()”结尾。
不难发现,函数名称中的这些字母的意思是:
k:表示键,key的缩写a:表示键值关联的保持(数字类型的不保持),associative的缩写r:表示逆向或者翻转,reverse的缩写u:表示用户自定义,user的缩写
然后,从最初的sort()函数开始。如果加首字母A,表示索引关系保持有序,如果加首字母K,表示对键进行排序。从而形成第一梯度排序函数:
sort()、asort()、ksort()
这三个排序函数,如果都在“sort”前加字母R,表示降序排序。从而形成第二梯度排序函数:
rsort()、arsort()、krsort()
如果在第一个梯度的三个排序函数前面加上第一个字母U,会更简单。直接表示用户定义的排序序列的函数,即第三个梯度排序函数:
usort()、uasort()、uksort()
最后,剩下的四种功能排序可以归为第四种梯度排序功能,即综合排序,包括:
natsort()、natcasesort()、shuffle()、array_multisort()
通过这样的安排,估计你可以在更短的时间内对PHP的数组排序功能有更深入的了解。甚至,你可以逐渐理解当时设计PHP的初衷是多么的巧妙。
本文来自怀过往投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/644761.html