質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.86%

  • PHP

    18591questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

タイ順位を表示させたい

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 491

gsuisk

score 61

インデックス配列aには、得点が入っています。rsort($a); で得点を高い順に並べました。

ここで同じ点数があった場合、タイ順位として表示させたいです。

イメージとしては

1位:100
1位:100
3位:97
4位:95
5位:90
6位:88
6位:88
6位:88
9位:85


実装してみたのですが、同点のものが2つまでしかタイ順位になりません。

foreach ($a as $key => $value) {

  $pre = 0;

  if($key > 0){

    $pre = $key-1;

    if($value===$a[$pre]){
      echo ++$pre."位:{$value}";
    }else {
      echo ++$key."位:{$value}";
    }

  //キーが0(先頭)の時
  }else {
    echo ++$key."位:{$value}";
  }

echo "<br>";
}

結果はこのようになってしまいます。

1位:100
1位:100
3位:97
3位:97
4位:973位にならない
6位:90
6位:90
7位:90  ←6位にならない
8位:90  ←6位にならない
9位:90  ←6位にならない

原因がつかめずに困っています。どこに問題があるのでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+6

array_count_valuesというそのものズバリな関数があるんですよぉ。
タイプ数も短いし完璧だね!
もし配列の中身が生徒クラスのインスタンスみたいになっても、少しの工夫で実現出来るよ。

<?php
$a = [90,100,97,95,88,100,88,85,88];
rsort($a);

$rank = 1;
foreach (array_count_values($a) as $point => $count) {
  for ($i = 0; $i < $count; $i++) {
    echo "{$rank}位: {$point}\n";
  }
  $rank += $count;
}

結果

$ php test.php
1位: 100
1位: 100
3位: 97
4位: 95
5位: 90
6位: 88
6位: 88
6位: 88
9位: 85

「追記」
ユーザー的な情報を用いて出力できるよう修正してたよ。
この手法を使えば小数点等でも対応出来ると思うよ。

<?php
function array_count_by_kokugo ($arr) {
  $results = [];
  foreach ($arr as $it) {
    $key = (string)$it['kokugo'];
    if (!isset($results[$key])) $results[$key] = [];
    $results[$key][] = $it;
  }
  return $results;
}

$a = [
  ["name" => "a", "kokugo" => 80.5],
  ["name" => "b", "kokugo" => 100],
  ["name" => "c", "kokugo" => 81],
  ["name" => "d", "kokugo" => 100],
  ["name" => "e", "kokugo" => 90.5],
  ["name" => "f", "kokugo" => 90.5],
  ["name" => "g", "kokugo" => 90.5],
  ["name" => "h", "kokugo" => 87.5],
  ["name" => "g", "kokugo" => 80],
];
usort($a, function ($a, $b) {
  $a2 = $a['kokugo'];
  $b2 = $b['kokugo'];
  if ($a2 == $b2) return 0;
  return ($a2 < $b2) ? 1 : -1;
});

$rank = 1;
foreach (array_count_by_kokugo($a) as $point => $users) {
  foreach ($users as $user) {
    echo "{$rank}位: {$user['name']} ({$point})\n";
  }
  $rank += count($users);
}

?>

1位: d (100)
1位: b (100)
3位: f (90.5)
3位: g (90.5)
3位: e (90.5)
6位: h (87.5)
7位: c (81)
8位: a (80.5)
9位: g (80)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/05 19:32

    ありがとうございます。

    得点に少数があるのでエラーが出てしまいましたが、intやstringの時はこうしたほうが簡単にできますね。参考になります!

    キャンセル

  • 2017/10/06 14:33

    そうなると実践的にはsortとgroupByの処理作らなきゃダメそうだね。
    2nくらいの計算量に収まるように頑張ってみようかな。
    今晩くらいに追記しますよ。

    キャンセル

  • 2017/10/06 15:17

    連想配列 x floatに対応!
    小数点対応は`array_count_by_kokugo`からやることを削れば作れるよね。

    キャンセル

  • 2017/10/07 00:25

    丁寧にありがとうございます!試してみます!

    キャンセル

  • 2017/10/07 01:14

    $results[$key] = [];

    これは、$key(この場合得点)をキーとする多次元配列を宣言していて

    $results[$key][] = $it;

    これは、$keyを大元のキーとする3次元配列として[]の部分に$it(2次元配列)を代入する。

    という意味ですよね?

    なのでarray_count_by_kokugo($a)は3次元配列を作っているということですよね。
    1次元が得点、2次元が同点の人の数、3次元がそれぞれのnameとkokugo

    キャンセル

  • 2017/10/07 01:14

    とても勉強になります!

    キャンセル

  • 2017/10/07 09:01

    > $results[$key] = [];
    そうだね、先に配列で宣言しておかないとエラーでこけちゃうからね。

    > $results[$key][] = $it;
    これはPHPのイディオムで、配列の末尾に要素を追加する。
    http://php.net/manual/ja/function.array-push.php

    > なのでarray_count_by_kokugo($a)は3次元配列を作っているということですよね。
    そのとおり。
    PHPはMySQL等のDBと連携して、その結果を加工して出力することが多いんだ。
    その場合、大抵2次元配列として受け取る事になるから、実践的にはこのような配列操作が多くなる。

    キャンセル

  • 2017/10/08 15:12

    勉強になりました!ありがとうございました。

    キャンセル

checkベストアンサー

+5

++$preなので1つ前のキーに足しているだけになっています。
$rankなど別に順位を管理する変数を用意しておき、そちらに足しこんでいくと良いと思います。
個人的に見やすくするため、if-elseの条件を逆にしていますが、こんな感じでどうでしょう。

$rank = 1;
foreach ($a as $key => $value) {
    //キーが0(先頭)の時
    if($key == 0){
        echo $rank."位:{$value}";
    }else{
        $pre = $key-1; //ひとつ前の数値と比較
        if($value === $a[$pre]){ //同じなら同位
            echo $rank."位:{$value}";
        }else { //違えばrankに足しこんで次の順位
            $rank = 1+ $key;
            echo ($key+1)."位:{$value}";
        }
    }
    echo "<br>";
}


※一応、動作検証済みですが、不具合あったら言ってください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/05 19:28

    できました!ありがとうございます。

    蛇足になってしまうんですが、最後のelse部分は

    //$rank = 1+ $key;
    $rank=++$key;

    //echo ($key+1)."位:{$value}";
    echo $rank."位:{$value}";

    としても問題なく動作しましたが、$pre = $key-1; を $pre = --$key; とすると順位が1つずれます。
    (1位が2つある場合、次が3位でなく2位になる。)

    --$key は $key-1 を返していると思うのですが、なぜこのような挙動になるのでしょうか?

    キャンセル

  • 2017/10/05 19:47

    PHPマニュアルのhttp://php.net/manual/ja/language.operators.increment.php
    を読んだらわかるかもしれませんが、
    $keyから1を引いた値ではなく$keyが1引かれた値$keyを返しているからではないでしょうか。
    $pre = $key = $key-1; という意味ですね。

    キャンセル

  • 2017/10/07 00:19

    わかりました!

    $key=5;

    $pre = $key-1; //$pre=4 $key=5
    $pre = --$key; //$pre=4 $key=4

    --$key; とすると$preの値は問題なくても、$key自身の値は一つ減るので、

       //違えばrankに足しこんで次の順位
    $rank = 1+ $key;
    echo ($key+1)."位:{$value}";

    この部分で一つ小さい$keyに1が足されているということですね!

    キャンセル

  • 2017/10/07 00:23

    なぜ $rank = 1+ $key; は $rank=++$key; に変えても大丈夫なのかと考えていましたが、この部分以降で$keyを使うことがない(ループ処理の最後)だから$key自身の値が変化していても、動作上は問題なかったのですね!(次のループでは新しい$keyが使われるから)

    キャンセル

  • 2017/10/07 00:24

    ありがとうございました。もし私の解釈が間違っていたら返信いただけると嬉しいです。

    キャンセル

  • 2017/10/07 02:57

    そうですね。その解釈で間違いないと思います。
    あとは実際にデバッグ出力してみて値の変化をおってみることで
    説明を聞くよりも理解が進み、身になりますよ

    キャンセル

  • 2017/10/08 15:13

    わかりました!丁寧にありがとうございました。

    キャンセル

+3

例えば、こう考えてみてください
配列の中で自分より大きな数だけ抜き出して数え、それに1を足すと自分の順位

$a=[90,100,97,95,88,100,88,85,88];

foreach($a as $val){
  print getRank($a,$val)."位:".$val."<br>";
}

function getRank($arr,$num){
  return count(array_filter($arr,function($arg) use ($num){return $arg>$num;}))+1;
}


このロジックであれば並び替える必要はありません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PHP

    18591questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。