在PHP中,数组排序是数据处理中的常见操作,尤其在面对多维数组或者需要多条件排序的场景时,选择合适的排序函数尤为重要。arsort() 和 ksort() 是两个经常被联合使用的函数,通过它们的组合,可以实现对数组的值和键进行有序管理。本文将结合具体代码示例,详细讲解这两个函数如何联合使用以实现多条件排序。
arsort():对数组进行降序排序,保留键名,按“值”排序。
ksort():对数组按“键”进行升序排序,保留键值。
虽然这两个函数本质上是分别作用于“值”和“键”的排序,但在某些场景中,可以通过联合使用它们,实现更灵活的多条件排序逻辑。
假设有如下一个数组,表示多个用户的得分记录:
<span><span><span class="hljs-variable">$users</span></span><span> = [
</span><span><span class="hljs-string">'user3'</span></span><span> => [</span><span><span class="hljs-string">'score'</span></span><span> => </span><span><span class="hljs-number">85</span></span><span>, </span><span><span class="hljs-string">'time'</span></span><span> => </span><span><span class="hljs-number">120</span></span><span>],
</span><span><span class="hljs-string">'user1'</span></span><span> => [</span><span><span class="hljs-string">'score'</span></span><span> => </span><span><span class="hljs-number">92</span></span><span>, </span><span><span class="hljs-string">'time'</span></span><span> => </span><span><span class="hljs-number">110</span></span><span>],
</span><span><span class="hljs-string">'user2'</span></span><span> => [</span><span><span class="hljs-string">'score'</span></span><span> => </span><span><span class="hljs-number">85</span></span><span>, </span><span><span class="hljs-string">'time'</span></span><span> => </span><span><span class="hljs-number">100</span></span><span>],
</span><span><span class="hljs-string">'user4'</span></span><span> => [</span><span><span class="hljs-string">'score'</span></span><span> => </span><span><span class="hljs-number">92</span></span><span>, </span><span><span class="hljs-string">'time'</span></span><span> => </span><span><span class="hljs-number">130</span></span><span>],
];
</span></span>
现在的需求是:
首先按得分(score)降序排序;
若得分相同,则按完成时间(time)升序排序;
若得分和时间都相同,再按用户名(键名)升序排序。
为了实现复杂排序,可以使用 uasort() 结合自定义函数:
<span><span><span class="hljs-title function_ invoke__">uasort</span></span><span>(</span><span><span class="hljs-variable">$users</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'score'</span></span><span>] == </span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'score'</span></span><span>]) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'time'</span></span><span>] == </span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'time'</span></span><span>]) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-comment">// 留待后续使用ksort处理键名排序</span></span><span>
}
</span><span><span class="hljs-keyword">return</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'time'</span></span><span>] < </span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'time'</span></span><span>]) ? -</span><span><span class="hljs-number">1</span></span><span> : </span><span><span class="hljs-number">1</span></span><span>; </span><span><span class="hljs-comment">// 时间升序</span></span><span>
}
</span><span><span class="hljs-keyword">return</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'score'</span></span><span>] > </span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'score'</span></span><span>]) ? -</span><span><span class="hljs-number">1</span></span><span> : </span><span><span class="hljs-number">1</span></span><span>; </span><span><span class="hljs-comment">// 得分降序</span></span><span>
});
</span></span>
由于 uasort() 不影响键名的顺序,我们可以再用 ksort() 来对键名进行排序,但这一步只有在值相同时才有意义。可以利用中间转换结构:
<span><span><span class="hljs-comment">// 将排序后的数组按键重新分组</span></span><span>
</span><span><span class="hljs-variable">$temp</span></span><span> = [];
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$users</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$key</span></span><span> => </span><span><span class="hljs-variable">$value</span></span><span>) {
</span><span><span class="hljs-variable">$groupKey</span></span><span> = </span><span><span class="hljs-variable">$value</span></span><span>[</span><span><span class="hljs-string">'score'</span></span><span>] . </span><span><span class="hljs-string">'-'</span></span><span> . </span><span><span class="hljs-variable">$value</span></span><span>[</span><span><span class="hljs-string">'time'</span></span><span>];
</span><span><span class="hljs-variable">$temp</span></span><span>[</span><span><span class="hljs-variable">$groupKey</span></span><span>][</span><span><span class="hljs-variable">$key</span></span><span>] = </span><span><span class="hljs-variable">$value</span></span><span>;
}
</span><span><span class="hljs-comment">// 对每组键名排序</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$temp</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> &</span><span><span class="hljs-variable">$group</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">ksort</span></span><span>(</span><span><span class="hljs-variable">$group</span></span><span>); </span><span><span class="hljs-comment">// 键名升序</span></span><span>
}
</span><span><span class="hljs-comment">// 合并成最终结果</span></span><span>
</span><span><span class="hljs-variable">$final</span></span><span> = [];
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$temp</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$group</span></span><span>) {
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$group</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$k</span></span><span> => </span><span><span class="hljs-variable">$v</span></span><span>) {
</span><span><span class="hljs-variable">$final</span></span><span>[</span><span><span class="hljs-variable">$k</span></span><span>] = </span><span><span class="hljs-variable">$v</span></span><span>;
}
}
</span></span>
此时,$final 就是我们期望的,按照 score 降序、time 升序、键名升序排列的结果。
在实际项目中,也可以将数据拍平、引入排序权重,结合 array_multisort() 来操作,但这种方法对保持键名不太友好。联合使用 arsort 和 ksort 的方式,则可以保留关联数组的完整结构和键名。
arsort() 和 ksort() 本身并不能直接支持多条件排序,但通过分组处理与多步排序逻辑,结合 uasort() 等函数,可以灵活地实现类似 SQL 中的 ORDER BY col1 DESC, col2 ASC 的效果。掌握这些排序技巧,有助于开发者在处理复杂数组数据时更加得心应手。