
本文详细介绍了如何使用 php 的 `usort` 函数对多维数组进行复杂排序。通过自定义比较逻辑,我们能够实现先按一个主键(如 `counted` 字段)进行降序排序,然后对主键值相同的元素再按另一个次键(如 `placement` 字段)进行升序排序,从而满足多级排序的需求。
在 PHP 开发中,我们经常会遇到需要对包含多个字段的多维数组进行复杂排序的场景。例如,一个数组需要首先根据某个字段进行分组或排序,然后对于分组内(即该字段值相同)的元素,再根据另一个字段进行二次排序。这种需求无法通过简单的 sort() 或 asort() 函数实现,而需要借助 usort() 函数的强大自定义能力。
PHP usort() 函数简介
usort() 函数使用用户自定义的比较函数对数组中的值进行排序。它的语法如下:
usort(array &$array, callable $callback): bool登录后复制
其中:
$array:要排序的数组,usort() 会直接修改原数组。$callback:一个回调函数,用于比较两个元素。这个回调函数接受两个参数 $a 和 $b,分别代表数组中的两个待比较元素。如果 $a 应该排在 $b 之前,函数应返回一个负整数(例如 -1)。如果 $a 应该排在 $b 之后,函数应返回一个正整数(例如 1)。如果 $a 和 $b 的顺序无关紧要(即它们相等),函数应返回 0。PHP 7 引入的飞船操作符 (<=>) 可以方便地实现这个比较逻辑。实现多级条件排序
假设我们有一个包含用户数据和统计信息的数组,每个元素都包含 id、placement 和 counted 等字段。我们的目标是:
立即学习“PHP免费学习笔记(深入)”;
首先,根据 counted 字段进行降序排序(counted 值越大越靠前)。然后,如果 counted 字段值相同,则根据 placement 字段进行升序排序(placement 值越小越靠前)。以下是原始数组示例:
$array = [ [ 'id' => 1, 'placement' => 8, 'counted' => 3, 'user' => ['name' => 'foo'], ], [ 'id' => 2, 'placement' => 5, 'counted' => 3, 'user' => ['name' => 'bar'], ], [ 'id' => 3, 'placement' => 1, 'counted' => 2, 'user' => ['name' => 'foobar'], ]];登录后复制
期望的排序结果是:
简篇AI排版 AI排版工具,上传图文素材,秒出专业效果!
554 查看详情
[ [ 'id' => 2, 'placement' => 5, 'counted' => 3, 'user' => ['name' => 'bar'], ], [ 'id' => 1, 'placement' => 8, 'counted' => 3, 'user' => ['name' => 'foo'], ], [ 'id' => 3, 'placement' => 1, 'counted' => 2, 'user' => ['name' => 'foobar'], ]]登录后复制
可以看到,counted 为 3 的元素排在 counted 为 2 的元素之前。而在 counted 都为 3 的两个元素中,placement 为 5 的元素排在 placement 为 8 的元素之前。
编写自定义比较函数
为了实现上述排序逻辑,我们可以这样编写 usort 的回调函数:
usort($array, function ($a, $b) { // 第一步:比较 'counted' 字段,按降序排列 // 如果 $a['counted'] 大于 $b['counted'],则 $a 应该排在 $b 前面,返回 -1。 // 如果 $a['counted'] 小于 $b['counted'],则 $a 应该排在 $b 后面,返回 1。 // 使用飞船操作符 <=>,为了降序,我们比较 $b['counted'] 和 $a['counted']。 $countedComparison = $b['counted'] <=> $a['counted']; // 如果 'counted' 字段不相等,直接返回比较结果 if ($countedComparison !== 0) { return $countedComparison; } // 第二步:如果 'counted' 字段相等,则比较 'placement' 字段,按升序排列 // 如果 $a['placement'] 小于 $b['placement'],则 $a 应该排在 $b 前面,返回 -1。 // 如果 $a['placement'] 大于 $b['placement'],则 $a 应该排在 $b 后面,返回 1。 // 如果两者相等,返回 0。 return $a['placement'] <=> $b['placement'];});// 打印排序后的数组print_r($array);登录后复制完整示例代码
将原始数组和排序逻辑结合起来,完整的示例代码如下:
<?php$array = [ [ 'id' => 1, 'placement' => 8, 'counted' => 3, 'user' => ['name' => 'foo'], ], [ 'id' => 2, 'placement' => 5, 'counted' => 3, 'user' => ['name' => 'bar'], ], [ 'id' => 3, 'placement' => 1, 'counted' => 2, 'user' => ['name' => 'foobar'], ]];echo "原始数组:\n";print_r($array);usort($array, function ($a, $b) { // 主键排序:'counted' 降序 $countedComparison = $b['counted'] <=> $a['counted']; if ($countedComparison !== 0) { return $countedComparison; } // 次键排序:'placement' 升序 (仅当 'counted' 相等时) return $a['placement'] <=> $b['placement'];});echo "\n排序后的数组:\n";print_r($array);?>登录后复制运行上述代码,将得到与预期输出一致的结果。
注意事项
usort() 会修改原数组:与 sort()、asort() 等函数类似,usort() 是一个原地排序函数,它会直接修改传入的数组,而不是返回一个新的排序后的数组。比较函数的返回值:务必确保自定义比较函数严格遵循返回 -1、0、1 的约定。不明确的返回值可能导致排序结果不一致或错误。飞船操作符 (<=>) 是一个非常好的选择,因为它天然地返回这三个值。数据类型:在比较字段值时,确保它们的数据类型是可比较的。例如,如果 counted 或 placement 字段的值可能是字符串,但实际上代表数字,最好在比较前进行类型转换(如 (int)$a['counted']),以避免字符串比较带来的非预期结果。在本例中,由于值是数字,PHP 会自动进行数值比较。性能考虑:对于包含大量元素或比较逻辑非常复杂的数组,自定义排序可能会带来一定的性能开销。在处理极端情况时,可能需要考虑其他优化策略,例如先使用其他方法进行部分预处理或分组。总结
通过 usort() 函数及其自定义比较回调,PHP 提供了强大的能力来处理多维数组的复杂排序需求。理解比较函数的返回值约定,并结合飞船操作符 (<=>),可以清晰且高效地实现多级条件排序,极大地提升了数据处理的灵活性。掌握这一技巧,对于处理各种复杂的数据结构和业务逻辑至关重要。
以上就是PHP多维数组的复杂排序:按主键分组后按次键排序的详细内容,更多请关注php中文网其它相关文章!



