You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:55:25