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>