2010/10/29
同じ点数の場合は同じ順位とし、その後下回る点数の者の
順位は、同点の人数分だけ下がる。
たとえば、2人が同点の1位なら、次の順位者は3位となる。
下記はその仕組みを実現するためのコード。
$rank = 0; //算出される順位 $reserve = 1; //キャリーオーバー用 $prev = -1; //初回は必ず不一致となる値(国語の点数) for ($i = 0; $i < count($list); $i++) { if ($list['国語'] == $prev) { //前回と同じ点数ならキャリーオーバー $reserve++; } else { //不一致なら、順位の持ち越し分を足し合わせる $rank = $rank + $reserve; //キャリーオーバーの値をリセット $reserve = 1; //現在の値を『前回の値』として記憶 $prev = $list['国語']; } //順位が表示される echo $rank; }
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>【PHP】順位を算出</title> <style type="text/css"> table, th, td { border: 1px solid #999; border-collapse: collapse; } th, td { padding: 4px 8px; } th { background: #def; } </style> </head> <body> <?php //------------------------------------------ //下準備 //------------------------------------------ //教科の配列と、テーブルのカラム名の配列を用意 $subjects = array('kokugo', 'sansuu'); $fields = array_merge(array('name', 'num'), $subjects); //ポイント順位一覧表の配列を用意 $list = array(); //------------------------------------------ //DB処理 (全情報を取得) //------------------------------------------ $db = new PDO('sqlite:database.sqlite3'); $sql = 'SELECT * FROM exam'; $statement = $db->prepare($sql); $statement->setFetchMode(PDO::FETCH_ASSOC); $statement->execute(); $list = $statement->fetchAll(); //------------------------------------------ //比較関数(教科ごとの点数用) //------------------------------------------ function compareSubject($val1, $val2) { global $subject; if ($val1[$subject] == $val2[$subject]) return 0; //数の小さい順に return ($val1[$subject] < $val2[$subject]) ? -1 : 1; } //------------------------------------------ //各教科のポイントを算出 //------------------------------------------ foreach($subjects as $subject) { //教科ごとの点数順に並べ替える usort($list, 'compareSubject'); $point = 0; $reserve = 1; $prev = -1; //初回は必ず不一致となる値 $max = count($list); for ($i=0; $i<$max; $i++) { if ($list[$i][$subject] == $prev) { $reserve++; } else { $point = $point + $reserve; $reserve = 1; $prev = $list[$i][$subject]; } if (isset($list[$i]['point'])) { //ポイントに加算 $list[$i]['point'] += $point; } else { //新規にポイント欄を作成 $list[$i]['point'] = $point; } $list[$i][$subject.'_pt'] = $point; } } //------------------------------------------ //比較関数(総合ポイント用) //------------------------------------------ function comparePoint($val1, $val2) { global $subject; if ($val1['point'] == $val2['point']) return 0; //数の大きい順に return ($val1['point'] > $val2['point']) ? -1 : 1; } //総合ポイント順に並べ替える usort($list, 'comparePoint'); //------------------------------------------ //順位を決定 //------------------------------------------ $max = count($list); $tensuu; $rank = 0; $reserve = 1; $prev = -1; //初回は必ず不一致となる値 for ($i=0; $i<$max; $i++) { if ($list[$i]['point'] == $prev) { $reserve++; } else { $rank = $rank + $reserve; $reserve = 1; $prev = $list[$i]['point']; } $list[$i]['rank'] = $rank; //↓$tensuu['name'][1][0]で、1位を表示 $tensuu['name'][$rank][] = $list[$i]['name']; $tensuu['num'][$rank][] = $list[$i]['num']; } ?> <!-- 集計結果をテーブルで表示 --> <table> <thead> <tr> <th>受験番号</th><th>名前</th><th>国語</th><th>算数</th> <th>国語pt</th><th>算数pt</th><th>総合ポイント</th><th>順位</th> </tr> </thead> <tbody> <?php foreach ($list as $val) : ?> <tr> <td><?php echo $val['num'] ?></td> <td><?php echo $val['name'] ?></td> <td><?php echo $val['kokugo'] ?></td> <td><?php echo $val['sansuu'] ?></td> <td><?php echo $val['kokugo_pt'] ?></td> <td><?php echo $val['sansuu_pt'] ?></td> <td><?php echo $val['point'] ?></td> <td><?php echo $val['rank'] ?></td> </tr> <?php endforeach ?> </tbody> </table> <?php echo '<pre>'; print_r($tensuu); echo '</pre>'; ?> </body> </html>