php仿excel的rank函数也是借鉴网上的代码,但是没有二维数组情况下的进行rank排名,所以自己对代码稍微改了一下,可以直接运行试验。

<?php
$arr = array(
          array('s'=>'99','r'=>'1','a'=>'a'),
          array('s'=>'99','r'=>'1','b'=>'b'),
          array('s'=>'100','r'=>'2','c'=>'c'),
          array('s'=>'101','r'=>'3','d'=>'d')
        );

echo '<pre>';
print_r(rank($arr,'s','r'));

//获得一组数的名次的数组
function rank(array $array,$s,$r){
        foreach($array as $k=>$v){
          $marr[] = $v[$s];
        }
        foreach($array as $val){
          $repeat=get_array_repeats($val[$s],$marr);
          $num=gt_array_values($val[$s],$marr);
          $rank[$r]=count($marr)-$num-$repeat+1;
          $rank2[] = array_merge($val,$rank);
        }
        return $rank2;
}

//获得比自己数小的个数
function gt_array_values($val,array $array){
        $num=0;
        for($i=0;$i<count($array);$i++){
                if($val>$array[$i]){
                        $num++;
                }
        }
        return $num;
}
//获得这个数的重复次数

function get_array_repeats($string,array $array) {
        $count = array_count_values($array);
        foreach ($count as $key => $value) {
                 if ($key == $string) {
                  return $value;
                  }
         }
}

逻辑也很简单,学生的名次,等于总人数减去比自己成绩低的人数,再减去和自己成绩一样的人数,再加一。

比自己成绩低的人数,和与自己成绩一样多的人数,分别是两个独立的函数,前者需要循环所有学生成绩,比自己成绩低的进行人数累加,每个学生都要进行这个循环,有点耗性能哈。后者只是单纯引用数组函数解决问题。

这样就可以根据考试成绩(字段名s),得到考生的排名(字段名r),但是很明显循环次数有点多,难以想象当数据量很大的时候情况是怎样的。

如果不考虑二维数组的情况,有大神提出可以这样写:

$arr = array(195,180,180,161);

function rt($arr){
    $temp = $arr;
    rsort($temp);
    $temp = array_unique($temp);
    foreach ($arr as $k1 => $v1) {
        foreach ($temp as $k2 => $v2) {
            if($v1==$v2){
                $res[$k1] = $k2+1;
            }
        }
    }
    return $res;
}

至于原理,说白了,rsort这个函数直接帮你把排名都排好了,键是排名,值是分数,是不是这个道理。然后循环原数组,分数一样的,把这个排名取出来就行了。

至于这种方法,二维数组的时候要怎么弄,这个需要二维数组里的分数值先按顺序排好,(这是另外一种算法),然后套用。

当然,这个方法理论上比上一个方法效率好多了。

另外查询的时候还可以直接执行sql语句实现rank函数功能,这个网上有不少例子,如MySQL中rank函数如何实现

    在这个例子中,当我们要查找id为1的学员的rank值的时候,直接运行sql语句如下:

select 
tmp.id,tmp.name,tmp.score,
@j:=@j+1 as j,
@k:=(case when @pre_score=tmp.score then @k else @j end) as rank,
@pre_score:=tmp.score as pre_score
from 
(
select * from score where id =1
) as tmp,
(select @k :=0,@j:=0, @pre_score:=0)
as mscore

j是顺序号,k是rank值

@k:=(case when @pre_score=tmp.score then @k else @j end

这句话意思是只有在前后二次排序值不同时才会使用顺序号,是关键的地方。

最后运行sql,用getRow函数得到id为1的这条数据,得到rank值。

转载于:https://blog.51cto.com/1105190775/1891460