PHP如何修改sortBySubValue函数实现多层子数组排序
PHP按二维关联数组的子数组字段多层排序问题
问题描述
我之前参考过相关实现,打算复用Pigalev Pavel提供的sortBySubValue函数实现排序,但我的场景里待排序的字段是一层子数组,调用函数后排序没有生效。
我的数组结构如下:
$players = array( array( "name" => "Woods", "countback" => array( "9" => 17, "6" => 11, "3" => 6, "1" => 2 ) ), array( "name" => "Spieth", "countback" => array( "9" => 17, "6" => 12, "3" => 4, "1" => 2 ) ), array( "name" => "McIlroy", "countback" => array( "9" => 17, "6" => 12, "3" => 5, "1" => 1 ) ), array( "name" => "Johnson", "countback" => array( "9" => 17, "6" => 12, "3" => 5, "1" => 2 ) ) );
我需要按照countback子数组的键序(按9、6、3、1的顺序依次比对)降序排列父数组,预期排序结果:
- Johnson 排第一,最后一级比对值2最高
- McIlroy 排第二,最后一级比对值1更低
- Spieth 排第三,第三级比对值4低于剩余选手
- Woods 排第四,第二级比对值11低于其他选手
原函数代码如下:
/** * @param array $array * @param string $value * @param bool $asc - ASC (true) or DESC (false) sorting * @param bool $preserveKeys * @return array * */ function sortBySubValue($array, $value, $asc = true, $preserveKeys = false) { if (is_object(reset($array))) { $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) { return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1); }) : usort($array, function ($a, $b) use ($value, $asc) { return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1); }); } else { $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) { return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1); }) : usort($array, function ($a, $b) use ($value, $asc) { return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1); }); } return $array; }
我直接调用后打印原$players数组,顺序没有变化。
解决方案
排序不生效的问题修复
原函数不会修改传入的原数组,而是返回排序后的新数组,你需要接收函数返回值,而不是直接打印原数组:
$sortedPlayers = sortBySubValue($players, 'countback', false); print_r($sortedPlayers);
多层子数组比对适配
PHP内置的数组比较运算符<=>本身就支持按元素顺序逐层比对,正好匹配你的countback排序规则,不需要修改原函数的核心逻辑,只要确认countback数组的键顺序是你要比对的优先级顺序即可(你的示例里键序正好是9、6、3、1,符合要求)。
如果后续需要自定义比对的键顺序,可以调整回调逻辑手动指定比对优先级:
// 手动指定比对的键优先级示例 $sortKeys = ['9','6','3','1']; foreach ($sortKeys as $key) { if ($a['countback'][$key] != $b['countback'][$key]) { return ($a['countback'][$key] <=> $b['countback'][$key]) * ($asc ? 1 : -1); } } return 0;
内容的提问来源于stack exchange,提问作者jingo_man
相关产品推荐
相关产品推荐

