PHP里处理数组排序的函数不少,sort()、usort()、ksort()各有各的适用场景。但遇到“一个数组排序后,另一个数组要跟着保持对应关系”这种需求时,前面几个函数就有点力不从心了。array_multisort()就是为这种场景准备的。它从PHP4.0开始就存在,算得上是PHP数组排序体系里一个比较扎实的工具。
这个函数的名字直译过来就是“数组多排序”,它既可以一次对多个数组进行排序,也可以对多维数组的各个维度进行排序。关键在于,排序之后数组之间的元素对应关系会被保留下来,这一点在很多实际业务里很有用。
语法结构
bool array_multisort (
array &$array1 [, mixed $array1_sort_order = SORT_ASC
[, mixed $array1_sort_flags = SORT_REGULAR
[, mixed $... ]]]
);
第一个参数是必须的,后面可以继续追加数组,也可以穿插排序顺序和排序类型参数。返回值是布尔型,成功返回true,失败返回false。
参数说明
| 参数 | 说明 | 是否必须 |
|---|---|---|
| array1 | 指定要排序的数组 | 必须 |
| 排序顺序 | SORT_ASC升序(默认),SORT_DESC降序 | 可选 |
| 排序类型 | SORT_REGULAR常规比较(默认)、SORT_NUMERIC数值比较、SORT_STRING字符串比较、SORT_LOCALE_STRING基于当前区域设置比较、SORT_NATURAL自然排序、SORT_FLAG_CASE可与SORT_STRING或SORT_NATURAL按位或组合实现不区分大小写 | 可选 |
| array2 | 指定另一个数组 | 可选 |
| array3 | 指定另一个数组 | 可选 |
排序类型里SORT_NATURAL值得留意一下,它对应的是natsort()那种“自然顺序”,比如字符串里的数字会按数值大小来排,而不是按ASCII逐位比较。SORT_FLAG_CASE则适合处理大小写混在一起的字符串。
一个需要记住的行为
字符串键名会被保留,但数字键名会被重新索引,从0开始,每次加1。如果两个元素比较结果相等,它们在排序后数组里的相对顺序是不确定的。这一点在写依赖稳定排序的逻辑时要特别注意。
示例1:单数组排序
<?php
$players = array("sachin", "ganguly", "virat", "dhoni", "yuvraj", "umesh");
array_multisort($players);
print_r($players);
?>
输出:
Array
(
[0] => dhoni
[1] => ganguly
[2] => sachin
[3] => umesh
[4] => virat
[5] => yuvraj
)
单数组排序时,array_multisort()的效果和sort()类似,都是按升序重新索引。但array_multisort()的侧重点其实不在单数组,而在多数组的联动。
示例2:两个数组同步排序
<?php
$game1 = array("Dell", "Lenovo");
$game2 = array("Asus", "Acer");
array_multisort($game1, $game2);
print_r($game1);
print_r($game2);
?>
输出:
Array
(
[0] => Dell
[1] => Lenovo
)
Array
(
[0] => Asus
[1] => Acer
)
这个例子里,game1本身已经是升序,所以排序后没有变化。game1本身已经是升序,所以排序后没有变化。game2会按照game1排序后的对应关系重新排列。如果game1排序后的对应关系重新排列。如果game1的顺序变了,$game2也会跟着变。
示例3:相同值时的次级排序
<?php
$lang1 = array("php", "php", "java");
$lang2 = array("swift", "python", "perl");
array_multisort($lang1, $lang2);
print_r($lang1);
print_r($lang2);
?>
输出:
Array
(
[0] => java
[1] => php
[2] => php
)
Array
(
[0] => perl
[1] => python
[2] => swift
)
lang1里有两个"php",比较时相等。这时候arraymultisort()会继续比较lang1里有两个"php",比较时相等。这时候arraymultisort()会继续比较lang2对应位置的元素,用$lang2的顺序来决定这两个"php"的先后。这就是多数组排序的一个核心机制:前一列相等时,后一列作为次级排序依据。
示例4:分别指定排序方向
<?php
$lang1 = array("php", "php", "java");
$lang2 = array("swift", "perl", "python");
array_multisort($lang1, SORT_ASC, $lang2, SORT_DESC);
print_r($lang1);
print_r($lang2);
?>
输出:
Array
(
[0] => java
[1] => php
[2] => php
)
Array
(
[0] => python
[1] => swift
[2] => perl
)
这里lang1按升序排,lang1按升序排,lang2按降序排。两个"php"相等时,看lang2的降序结果,"swift"排在"perl"前面,所以对应的lang2的降序结果,"swift"排在"perl"前面,所以对应的lang2输出顺序是swift、perl。这种分别指定排序方向的能力,在处理多条件排序时比较实用。
本节课程知识要点
-
array_multisort()适合多数组同步排序,排序后数组间的元素对应关系保持不变。
-
第一个数组是主排序依据,后续数组在前一数组元素相等时充当次级排序依据。
-
可以为每个数组单独指定排序顺序和排序类型,参数按数组、顺序、类型的顺序成组出现。
-
字符串键名保留,数字键名重新索引。
-
相等元素的相对顺序不确定,依赖稳定排序的场景需要额外处理。
-
SORT_NATURAL和SORT_FLAG_CASE在处理字符串时能覆盖更多实际需求。
个人经验分享
实际项目里,我处理过一种场景:从数据库取出一批商品,需要按价格排序,价格相同的再按销量排序。用SQL的ORDERBY当然可以,但如果数据已经在PHP数组里,或者排序规则需要动态调整,array_multisort()就很顺手。把价格数组和销量数组一起传进去,价格升序、销量降序,一次调用就能拿到结果。
不过有一点要提醒:array_multisort()的参数顺序容易写错。数组、排序顺序、排序类型是按组出现的,如果多个数组都要指定顺序和类型,写变得比较长。这时候可以考虑先用array_column()把需要排序的列提取出来,再传给array_multisort(),代码会清晰很多。
如果只是单数组排序,用sort()或usort()就够了,没必要上array_multisort()。它的价值主要体现在“多个数组需要保持对应关系”这个点上。
小结
array_multisort()是PHP数组排序里一个比较有特色的函数。它不只是一个排序工具,更像是一个“按列排序”的机制。理解它的参数分组方式、次级排序逻辑和键名处理规则,就能在需要多数组联动排序时少走弯路。代码号学习编程建议在项目里多试几次不同参数组合,尤其是排序顺序和排序类型的搭配,熟悉之后会发现它比想象中好用。