すたらSample

【PHP】順位を算出

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>