PHP 数组排序
本文最后更新于:2024年3月18日 凌晨
PHP 数组排序
- 排序(sorting)改变了数组中元素的键名来反映新顺序,例如,可以使用排序来按从大到小排列一个得分清单,按字母表排列一个名字清单或根据用户提交的消息多少来排列一组用户。
- PHP提供三种对数组排序的方法:按键排序,不改变键的按值排序,按值排序并改变键,每种排序方式都可以按升序,降序或用户定义函数的顺序排序。
一次排序一个数组
效果 |
升序 |
降序 |
用户定义的顺序 |
按值排序数组,然后从0开始重新分配索引 |
sort() |
rsort() |
usort() |
按值排序 |
asort() |
arsort() |
uasort() |
按键排序 |
ksort() |
krsort() |
uksort() |
- 因为
sort()
,rsort()
和usort()
函数分配新的数字键来表示顺序,所以这些函数适用于索引数组(排列有序且连续),当需要回答像"前10名的分数是多少?"和"按字母排序的第三个人是谁?"这样的问题时,这些函数时很有用的,其他排序函数也可以用于索引数组,但是你只能使用诸如foreach和next这样的遍历函数来访问排列好的顺序。
- 要把名字按字母表升序排列,可以这样做:
1 2
| $names = array('cath','angela','brad','dave'); sort($name);
|
- 要按字母表降序得到它们,用
rsort()
代替sort()
即可。
- 假设有一个映射用户名到登录时间分钟数的关联数组,可以使用
arsort()
来显示表格的前3列,如下所示;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| $login = array('njt' => 415, 'kt' => 492, 'rl' => 652, 'jht' => 441, 'jj' => 441, 'wt' => 402); arsort($logins); $num_printed = 0; echo ("<table>\n"); foreach($logins as $user => $time){ echo("<tr><td>$user</td><td>$time</td></tr>\n"); if(++$num_printed == 3){ break; } } echo("</table>\n);
<table> <tr><td>rl</td><td>652</td></tr> <tr><td>kt</td><td>492</td></tr> <tr><td>jht</td><td>441</td></tr> </table>
|
- 如果想要表格按用户名的升序显示,使用
ksort()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| $login = array('njt' => 415, 'kt' => 492, 'rl' => 652, 'jht' => 441, 'jj' => 441, 'wt' => 402); ksort($logins); $num_printed = 0; echo ("<table>\n"); foreach($logins as $user => $time){ echo("<tr><td>$user</td><td>$time</td></tr>\n"); } echo("</table>\n);
<table> <tr><td>jht</td><td>441</td></tr> <tr><td>jj</td><td>441</td></tr> <tr><td>kt</td><td>492</td></tr> <tr><td>njt</td><td>415</td></tr> <tr><td>rl</td><td>652</td></tr> <tr><td>wt</td><td>402</td></tr> </table>
|
- 如果使用"用户自定义顺序",你需要提供一个函数,该函数接收两个值并返回指定排序数组中两个值的顺序,如果第一个值时函数返回1,如果第一个值小于第二个值则返回-1,如果两个值对于用户定义的顺序相等,则返回0
- 下例在相同的数据上尝试使用不同的排序函数。
示例5-3:数组排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <?php function user_sort($a,$b){ if($b == 'smarts'){ return 1; }else if($a == 'smarts'){ return -1; } return($a == $b) ? 0 : (($a < $b) ? -1 : 1); } $values = array('name' => 'Buzz Lightyear', 'email_address' => 'buzz@starcommand.gal', 'age' => 32, 'smarta' => 'some'); if($submitted){ if($sort_type == 'usort'||$sort_type == 'uksort'||$sort_type == 'uasort'){ $sort_type($values); } } ?> <form action="index.php" method="post"> <p> <input type="radio" name="sort_type" value="sort" checked="checked"/>Standard sort<br/> <input type="radio" name="sort_type" value="rsort" />Reverse sort<br/> <input type="radio" name="sort_type" value="usort" />User-defined sort<br/> <input type="radio" name="sort_type" value="ksort" />Key sort<br/> <input type="radio" name="sort_type" value="krsort" />Reverse key sort<br/> <input type="radio" name="sort_type" value="uksort" />User-defined key sort<br/> <input type="radio" name="sort_type" value="asort" />Value sort<br/> <input type="radio" name="sort_type" value="arsort" />Value Reverse sort<br/> <input type="radio" name="sort_type" value="uasort" />User-defined Value sort<br/> </p> <p align="center"> <input type="submit" value="Sort" name="submitted"/> </p> <p> Values<?=$submitted ? "sorted by $sort_type" : "unsorted";?>: </p> <ul> <?php foreach($values as $key => $value){ echo "<li><b>$key</b>:$value</li>"; } ?> </ul> </form>
|
按自然顺序排序
- PHP的内置排序函数可以正确排序字符串和数组,但是不能对含有数字的字符串正确排序,例如,如果有文件名:ex10php,ex5.php和ex1.php,一般的排序函数会把它们按这样排序:ex1.php,ex10.php,ex5.php,要对含有数字的字符串正确排序,应使用
natsort()
和natcasesort()
函数:
1 2
| $output = natsort(input); $output = natcasesort(input);
|
一次对多个数组排序
array_multisort()
函数可以一次对多个索引数组排序:
1
| array_multisort(array1[,array2,...]);
|
- 函数接收一系列数组并排序(通过
SORT_ASC
或SORT_DESC常
量确定),函数对所有数组的元素重新排序并分配新的索引,这类似于关系型数据库中的结合(join)操作。
- 假设有许多人,并且每个人有若干条数据:
1 2 3
| $names = array('Tom','Dick','Harriet','Brenda','Joe'); $ages = array(25,35,29,35,35); $zips = array(80522,'02140',90210,64141,80522);
|
- 每个数组的第一个元素描述一个单独的记录----关于Tom的所有信息,类似的,第二个元素组成另一个记录----关于Dick的所有信息,
array_multisort()
函数重新排序数组的元素,并保留记录,也就是说,如果Dick在$names数组排序后是第一位,Dick的其余信息也将在其他数组的第一位(注意我们需要将Dick的邮政编码加上引号来防止它被当作一个八进制常量)
- 下面先按年龄升序排列记录,然后按邮政编码降序排序记录:
1
| array_multisort($ages,SORT_ASC,$zips,SORT_DESC,$names,SORT_ASC);
|
- 我们需要在函数调用中包含
$names
来确保Dick的姓名,年龄及邮政编码在一起,排序结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| echo("<table>\n"); for($i = 0;$i < count($names);$i++){ echo("<tr><td>$ages[$i]</td><td>$zips[$i]</td><td>$names[$i]</td>\n"); } echo("</table>\n");
<table> <tr><td>25</td><td>80522</td><td>Tom</td> <tr><td>29</td><td>90210</td><td>Harriet</td> <tr><td>35</td><td>80522</td><td>Joe</td> <tr><td>35</td><td>64141</td><td>Brenda</td> <tr><td>35</td><td>02140</td><td>Dick</td> </table>
|
翻转数组
array_reverse()
函数翻转数组中元素的内部顺序:
1
| $reveresed = array_reverse(array);
|
- 数字索引从0开始重新编号,字符串索引则不受影响,一般来说,用翻转顺序的排序函数比排序后再翻转数组顺序好。
array_flip()
函数返回数组,它翻转了每个元素的键-值对的顺序(键值互换):
1
| $flipped = array_flip(array);
|
- 也就是说,数组中的每个元素来说,如果它的键值是合法的键,则该元素的值将变成为它的键并且该元素的键成为它的值。
- 例如,如果有一个数组映射用户名到主目录,可以使用
array_flip()
来创建一个映射主目录到用户名的数组:
1 2 3 4 5 6
| $u2h = array('gnat' => '/home/staff/nathan', 'rasmus' => '/home/elite/rasmus', 'petermac' => '/home/staff/petermac', 'ktatroe' => '/home/staff/kevin'); $h2u = array_flip($u2h); $user = $h2u['/home/staff/kevin'];
|
- 如果元素的值既不是字符串也不是整数,则该元素被留在结果数组中,新数组中元素的键名在原始数组的值中(但只有当原始数组的元素值都唯一,互不相等才行,如果原数组中有几个元素的值相等,则互换后最后一个键名将作为它的值,所有其他键名的都将丢失)
随机顺序
- 要按随机顺序遍历数组的元素,可以使用
shuffle()
函数,所有存在的键无论是字符串还是数字,都将被从零开始的连续整数代替。
- 下面是如何随机排序星期中的日期:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $days = array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'); shuffle($days); print_r($days);
Array ( [0] => Tuesday [1] => Thursday [2] => Monday [3] => Friday [4] => Wednesday [5] => Saturday [6] => Sunday )
|
- 很显然,你执行
shuffle()
后的顺序发可能和例子输出不一样,除非你对从一个数组中可以不重复地取出多个随机元素感兴趣,否则使用rand()
来取得一个索引会更有效率(但rand()
取得索引可能会重复)