php 对具有潜在重复值的数组值进行排名,如果出现平局则跳过某些位置

toiithl6  于 2023-01-19  发布在  PHP
关注(0)|答案(4)|浏览(93)

我正在处理操纵大学生考试结果的数据库数据。基本上,我从MySQL数据库中提取记录,并在任何给定时间提取一个类。我想给1排名,以最高成绩排名学生。
这里有一个例子

Marks: 37, 92, 84, 83, 84, 65, 41, 38, 38, 84.

我希望将MySQL数据捕获为一个数组。一旦我将数据放入数组中,我就应该为每个学生分配一个位置,例如1/10(排名第一,92分),4/10等。现在的问题是,如果出现平局,则下一个分数跳过一个位置,如果在一个位置有3个分数,则下一个分数跳过2个位置,因此以上分数将被排序如下:

92 - 1
84 - 2,
84 - 2,
84 - 2,
83 - 5,
65 - 6,
41 - 7,
38 - 8,
38 - 8 ,
37 - 10

评分系统要求保持职位数量(如果你愿意,可以说是级别)不变,所以我们在这个类中有10个职位,因为职位3、4、5和9没有任何人(如果选择填满每个数字,我们只会得到8个职位!)
有没有可能(人工/编程可能)用PHP来排列上面的分数,这样它就可以处理可能的平局,比如一个位置上有4个分数?遗憾的是,我不能想出一个函数来做这件事。我需要一个PHP函数(或PHP中的某个函数),它将接受一个数组并产生上面的排名。
如果可以对MySQL查询数据执行此操作,而无需将其放在数组中,那么这也会很有帮助!

c9qzyr3d

c9qzyr3d1#

我假设成绩已经按数据库排序,否则使用sort($grades);

    • 代码:**
$grades = array(92, 84, 84, 84, 83, 65, 41, 38, 38, 37);
$occurrences = array_count_values($grades);
$grades = array_unique($grades);
foreach($grades as $grade) {
    echo str_repeat($grade .' - '.($i+1).'<br>',$occurrences[$grade]);
    $i += $occurrences[$grade];
}
    • 结果:**
92 - 1
84 - 2
84 - 2
84 - 2
83 - 5
65 - 6
41 - 7
38 - 8
38 - 8
37 - 10
    • 编辑***(对以下讨论的回应)*

显然,万一平局发生在最低分,
所有最低分数的等级应该等于分数的总数。
代码:

$grades = array(92, 84, 84, 84, 83, 65, 41, 38, 37, 37);
$occurrences = array_count_values($grades);
$grades = array_unique($grades);
foreach($grades as $grade) {
    if($grade == end($grades))$i += $occurrences[$grade]-1;
    echo str_repeat($grade .' - '.($i+1).'<br>',$occurrences[$grade]);
    $i += $occurrences[$grade];
}

结果:

92 - 1
84 - 2
84 - 2
84 - 2
83 - 5
65 - 6
41 - 7
38 - 8
37 - 10
37 - 10
h9vpoimq

h9vpoimq2#

$scores = array(92, 84, 84, 84, 83, 65, 41, 38, 38, 37);
$ranks = array(1);
for ($i = 1; $i < count($scores); $i++)
{
    if ($scores[$i] != $scores[$i-1])
        $ranks[$i] = $i + 1;
    else
        $ranks[$i] = $ranks[$i-1];
}
print_r($ranks);
qf9go6mv

qf9go6mv3#

我需要最终得到一个值到排名的Map。这个方法可能对原来的问题也更有效。

public static function getGrades($grades)
{
    $occurrences = array_count_values($grades);
    krsort($occurrences);

    $position = 1;
    foreach ($occurrences as $score => $count) {
        $occurrences[$score] = $position;
        $position += $count;

    }

    return $occurrences;
}

如果在$个示例上打印_r,则会得到

Array
(
    [92] => 1
    [84] => 2
    [83] => 5
    [65] => 6
    [41] => 7
    [38] => 8
    [37] => 10
)

基于原来的答案,所以谢谢!

t3psigkw

t3psigkw4#

使用array_count_values()后接foreach()是在输入数组上执行2个循环,但是这个任务可以在一个循环中完成(最小化/优化时间复杂度)。
代码:(Demo

// assumed already rsort()ed.
$scores = [92, 84, 84, 84, 83, 65, 41, 38, 38, 37];

$gappedRank = 0;
$result = [];
foreach ($scores as $score) {
    ++$gappedRank;
    $gappedRanks[$score] ??= $gappedRank;
    $result[] = [$score => $gappedRanks[$score]];
}
var_export($result);

对于分数及其排名的平面关联查找数组,无条件地递增计数器,并且仅当键是新的时才将新元素推入查找数组。(Demo

$gappedRank = 0;
$lookup = [];
foreach ($scores as $score) {
    ++$gappedRank;
    $lookup[$score] ??= $gappedRank;
}
var_export($lookup);

第一个片段提供了"gapped ranking"。我有另一个答案,它实现了类似的方法,但使用了不同的输入数据结构,并在循环时修改行数据。

在排名领域,也有"密集排名"。请参阅我的时间复杂度优化答案:

相关问题