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

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

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

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

Q&A

解決済

3回答

7029閲覧

タイ順位を表示させたい

gsuisk

総合スコア72

PHP

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

0グッド

0クリップ

投稿2017/10/05 07:08

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

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

イメージとしては

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

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

PHP

1foreach ($a as $key => $value) { 2 3 $pre = 0; 4 5 if($key > 0){ 6 7 $pre = $key-1; 8 9 if($value===$a[$pre]){ 10 echo ++$pre."位:{$value}"; 11 }else { 12 echo ++$key."位:{$value}"; 13 } 14 15 //キーが0(先頭)の時 16 }else { 17 echo ++$key."位:{$value}"; 18 } 19 20echo "<br>"; 21}

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

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

PHP

1<?php 2$a = [90,100,97,95,88,100,88,85,88]; 3rsort($a); 4 5$rank = 1; 6foreach (array_count_values($a) as $point => $count) { 7 for ($i = 0; $i < $count; $i++) { 8 echo "{$rank}位: {$point}\n"; 9 } 10 $rank += $count; 11}

結果

Bash

1$ php test.php 21位: 100 31位: 100 43位: 97 54位: 95 65位: 90 76位: 88 86位: 88 96位: 88 109位: 85

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

PHP

1<?php 2function array_count_by_kokugo ($arr) { 3 $results = []; 4 foreach ($arr as $it) { 5 $key = (string)$it['kokugo']; 6 if (!isset($results[$key])) $results[$key] = []; 7 $results[$key][] = $it; 8 } 9 return $results; 10} 11 12$a = [ 13 ["name" => "a", "kokugo" => 80.5], 14 ["name" => "b", "kokugo" => 100], 15 ["name" => "c", "kokugo" => 81], 16 ["name" => "d", "kokugo" => 100], 17 ["name" => "e", "kokugo" => 90.5], 18 ["name" => "f", "kokugo" => 90.5], 19 ["name" => "g", "kokugo" => 90.5], 20 ["name" => "h", "kokugo" => 87.5], 21 ["name" => "g", "kokugo" => 80], 22]; 23usort($a, function ($a, $b) { 24 $a2 = $a['kokugo']; 25 $b2 = $b['kokugo']; 26 if ($a2 == $b2) return 0; 27 return ($a2 < $b2) ? 1 : -1; 28}); 29 30$rank = 1; 31foreach (array_count_by_kokugo($a) as $point => $users) { 32 foreach ($users as $user) { 33 echo "{$rank}位: {$user['name']} ({$point})\n"; 34 } 35 $rank += count($users); 36} 37 38?> 39 401位: d (100) 411位: b (100) 423位: f (90.5) 433位: g (90.5) 443位: e (90.5) 456位: h (87.5) 467位: c (81) 478位: a (80.5) 489位: g (80)

投稿2017/10/05 08:20

編集2017/10/06 06:11
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gsuisk

2017/10/05 10:32

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

2017/10/06 05:33

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

2017/10/06 06:17

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

2017/10/06 15:25

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

2017/10/06 16:14

$results[$key] = []; これは、$key(この場合得点)をキーとする多次元配列を宣言していて $results[$key][] = $it; これは、$keyを大元のキーとする3次元配列として[]の部分に$it(2次元配列)を代入する。 という意味ですよね? なのでarray_count_by_kokugo($a)は3次元配列を作っているということですよね。 1次元が得点、2次元が同点の人の数、3次元がそれぞれのnameとkokugo
gsuisk

2017/10/06 16:14

とても勉強になります!
miyabi-sun

2017/10/07 00: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次元配列として受け取る事になるから、実践的にはこのような配列操作が多くなる。
gsuisk

2017/10/08 06:12

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

0

ベストアンサー

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

php

1$rank = 1; 2foreach ($a as $key => $value) { 3 //キーが0(先頭)の時 4 if($key == 0){ 5 echo $rank."位:{$value}"; 6 }else{ 7 $pre = $key-1; //ひとつ前の数値と比較 8 if($value === $a[$pre]){ //同じなら同位 9 echo $rank."位:{$value}"; 10 }else { //違えばrankに足しこんで次の順位 11 $rank = 1+ $key; 12 echo ($key+1)."位:{$value}"; 13 } 14 } 15 echo "<br>"; 16} 17

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

投稿2017/10/05 07:29

m.ts10806

総合スコア80850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gsuisk

2017/10/05 10: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 を返していると思うのですが、なぜこのような挙動になるのでしょうか?
m.ts10806

2017/10/05 10:47

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

2017/10/06 15: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が足されているということですね!
gsuisk

2017/10/06 15:23

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

2017/10/06 15:24

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

2017/10/06 17:57

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

2017/10/08 06:13

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

0

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

PHP

1$a=[90,100,97,95,88,100,88,85,88]; 2 3foreach($a as $val){ 4 print getRank($a,$val)."位:".$val."<br>"; 5} 6 7function getRank($arr,$num){ 8 return count(array_filter($arr,function($arg) use ($num){return $arg>$num;}))+1; 9}

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

投稿2017/10/05 07:51

編集2017/10/05 07:53
yambejp

総合スコア114843

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問