PHP多维数组排名计算错误求助:求完整修正方案
PHP多维数组排名计算错误修复方案
问题说明
在处理多维数组的学生出勤率排名时,出现排名结果不符合预期的情况:例如stu_pres为71.67的学生实际应为第1名,但计算后显示为第4名。自行编写的calculate_rank函数未解决问题,现附上错误结果及代码,寻求正确实现。
当前错误的数组结果
Array ( [0] => Array ( [sturoll_no] => MAX001 [stu_name] => Name01 [stu_pres] => 70.00 [rank] => 1 ) [1] => Array ( [sturoll_no] => MAX002 [stu_name] => H.M.Dehan [stu_pres] => 53.33 [rank] => 2 ) [2] => Array ( [sturoll_no] => MAX003 [stu_name] => Chamudi [stu_pres] => 30.00 [rank] => 3 ) [3] => Array ( [sturoll_no] => MAX004 [stu_name] => D Laknara [stu_pres] => 71.67 [rank] => 4 ) [4] => Array ( [sturoll_no] => MAX005 [stu_name] => D M Imasha [stu_pres] => 21.67 [rank] => 5 ) [5] => Array ( [sturoll_no] => Max006 [stu_name] => Name05 [stu_pres] => 63.33 [rank] => 6 ) [6] => Array ( [sturoll_no] => MAX007 [stu_name] => Name06 [stu_pres] => 66.67 [rank] => 7 ) )
现有代码
$student_mark = [ [ 'reg_no' => 'REG_10001', 'student_name' => 'Rita Book', 'mark' => '89', ],[ 'reg_no' => 'REG_10002', 'student_name' => 'A. Mused', 'mark' => '95', ],[ 'reg_no' => 'REG_10003', 'student_name' => 'Rose Bush', 'mark' => '35', ],[ 'reg_no' => 'REG_10004', 'student_name' => 'Greg Arias', 'mark' => '86', ],[ 'reg_no' => 'REG_10005', 'student_name' => 'Skye Blue', 'mark' => '12', ],[ 'reg_no' => 'REG_10006', 'student_name' => 'Don Messwidme', 'mark' => '0', ],[ 'reg_no' => 'REG_10007', 'student_name' => 'Emma Grate', 'mark' => '0', ],[ 'reg_no' => 'REG_10008', 'student_name' => 'Sarah Moanees', 'mark' => '75', ],[ 'reg_no' => 'REG_10009', 'student_name' => 'Mal Nurrisht', 'mark' => '86', ],[ 'reg_no' => 'REG_10010', 'student_name' => 'Stanley Knife', 'mark' => '35', ], ]; $student_rank = calculate_rank($student_mark); //calculate rank for multi dimensional array function calculate_rank($rank_values): array { $rank = 0; $r_last = null; foreach ($rank_values as $key => $arr) { if ($arr['mark'] != $r_last) { if($arr['mark'] > 0){ //if you want to set zero rank for values zero $rank++; } $r_last = $arr['mark']; } $rank_values[$key]['rank'] = $arr['mark'] > 0 ? $rank: 0; //if you want to set zero rank for values zero } return $rank_values; }
问题根源
原函数的核心问题是未先对数组按分数/出勤率降序排序,直接按原数组顺序遍历计算排名,导致高分元素出现在后面时,排名会被错误地分配为后续序号。此外,原代码中的字段是mark,但实际使用的数组字段是stu_pres,字段名不统一也会导致逻辑失效。
完整解决方案
方案1:排序后计算排名(改变原数组顺序)
先将数组按目标字段(如stu_pres)降序排序,再遍历计算排名,同时处理并列排名的情况:
// 示例使用的学生出勤率数组 $student_pres = [ ['sturoll_no' => 'MAX001', 'stu_name' => 'Name01', 'stu_pres' => 70.00], ['sturoll_no' => 'MAX002', 'stu_name' => 'H.M.Dehan', 'stu_pres' => 53.33], ['sturoll_no' => 'MAX003', 'stu_name' => 'Chamudi', 'stu_pres' => 30.00], ['sturoll_no' => 'MAX004', 'stu_name' => 'D Laknara', 'stu_pres' => 71.67], ['sturoll_no' => 'MAX005', 'stu_name' => 'D M Imasha', 'stu_pres' => 21.67], ['sturoll_no' => 'Max006', 'stu_name' => 'Name05', 'stu_pres' => 63.33], ['sturoll_no' => 'MAX007', 'stu_name' => 'Name06', 'stu_pres' => 66.67], ]; $ranked_students = calculate_pres_rank($student_pres); print_r($ranked_students); function calculate_pres_rank($students): array { // 复制数组避免修改原数据 $sorted_students = $students; // 按stu_pres降序排序,将字符串转为数值避免比较错误 usort($sorted_students, function($a, $b) { return (float)$b['stu_pres'] <=> (float)$a['stu_pres']; }); $rank = 0; $last_pres = null; $position = 0; foreach ($sorted_students as $key => &$student) { $position++; $current_pres = (float)$student['stu_pres']; if ($current_pres !== $last_pres) { $rank = $position; $last_pres = $current_pres; } // 零出勤率设置为0排名,否则赋值计算出的排名 $student['rank'] = $current_pres > 0 ? $rank : 0; } return $sorted_students; }
方案2:保留原数组顺序的排名计算
如果需要保持原数组的顺序,可先提取所有出勤率值计算排名映射,再将排名赋值回原数组:
$student_pres = [ ['sturoll_no' => 'MAX001', 'stu_name' => 'Name01', 'stu_pres' => 70.00], ['sturoll_no' => 'MAX002', 'stu_name' => 'H.M.Dehan', 'stu_pres' => 53.33], ['sturoll_no' => 'MAX003', 'stu_name' => 'Chamudi', 'stu_pres' => 30.00], ['sturoll_no' => 'MAX004', 'stu_name' => 'D Laknara', 'stu_pres' => 71.67], ['sturoll_no' => 'MAX005', 'stu_name' => 'D M Imasha', 'stu_pres' => 21.67], ['sturoll_no' => 'Max006', 'stu_name' => 'Name05', 'stu_pres' => 63.33], ['sturoll_no' => 'MAX007', 'stu_name' => 'Name06', 'stu_pres' => 66.67], ]; $ranked_students = calculate_pres_rank_keep_order($student_pres); print_r($ranked_students); function calculate_pres_rank_keep_order($students): array { // 提取所有出勤率值并去重 $pres_values = array_unique(array_map(function($stu) { return (float)$stu['stu_pres']; }, $students)); // 降序排序 rsort($pres_values); // 创建出勤率到排名的映射 $rank_map = []; foreach ($pres_values as $index => $pres) { // 排名从1开始,零出勤率映射为0 $rank_map[$pres] = $pres > 0 ? ($index + 1) : 0; } // 为原数组每个元素赋值排名 foreach ($students as &$student) { $current_pres = (float)$student['stu_pres']; $student['rank'] = $rank_map[$current_pres] ?? 0; } return $students; }
关键说明
- 排序时必须将字符串类型的数值转为
float或int,避免字符串比较导致的逻辑错误(比如"71.67"和"70.00"字符串比较会得到错误结果)。 - 两种方案都处理了并列排名的情况:相同出勤率的学生获得相同排名。
- 可根据需求调整零出勤率的排名规则(当前设置为0,可改为最后一名等)。
内容的提问来源于stack exchange,提问作者kawshalya
相关产品推荐
相关产品推荐

