php和mysql仿excel的rank函數

    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值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章