人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

phpのkrsortについてです。
サッカーリーグの順位付けプログラムを作成中ですが、勝点、得失点差、総得点の順で重み付けをして数値化し、それをソートして順位順に並べようとしています。

foreach(...){
$team_data[] = array($omomi => array($name, $win_point, $get_loss, $point);
}
krsort($team_data);

上記のような配列を$omomiをキーとして重み数値を降順でソートしようとしていますが、間違いを教えてください。

●質問者: khaie
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● TransFreeBSD
●50ポイント

print_rすればわかりますが、$team_dataのキーが$omomiになってません。krsortを使うならforeachの中身は
$team_data[$omomi] = array($name, $win_point, $get_loss, $point);
です。
krsortは$team_dataのキーで逆順ソートしますので、$team_dataのキーが$omomiになるようにします。
この時、$omomiに重複が出ないよう末尾に$nameを付加するなど工夫が必要です。

ただ、krsortにこだわる必要はないですよね?
このデータ構造は多分使いやすくはないでしょう。

こういう場合は別に配列を用意して、
$team_data[$name] = array($win_point, $get_loss, $point);
$team_omomi[$name] = $omomi;
として$team_omomiをrsortし、$team_omomiのキーを使って$team_dataにアクセスする方法があります。
この場合は$nameから各種データへのアクセスがしやすくなります。

または、
$team_data[] = array("omomi" => $omomi, "name" => $name, "win_point" => $win_point, ...);
としてusortを使い

<?php
function cmp($a, $b)
{
 if ($a["omomi"] == $b["omomi"]) {
 return 0;
 }
 return ($a["omomi"] < $b["omomi"]) ? -1 : 1;
}
usort($team_data, "cmp");

などとして順位をキーとします。
この場合は順位からデータを求めやすいですが、$nameからのアクセスは悪くなります。

件数が何万とあるわけではないので、さほど効率は求めなくて良いと思いますから、用途に合わせデータ構造を考えた方がよいですよ。


a-kuma3さんのコメント
おっと、続きがありましたか <tt>:-)</tt>

khaieさんのコメント
キーの意味がよくわかっていなかったようです。

TransFreeBSDさんのコメント
すみません。 思わずチョロッとかいてから、流石にアレかと思い追記しました :->

2 ● a-kuma3
●100ポイント ベストアンサー

そもそも、krsort を使うところからずれています。
データの作り方も、ちょっと変。
usort か arsort を使うとスッキリします。

チーム名も含めて、チームのデータが配列になっている場合には、usort を使う。

<?php

// test data
$team_data[] = array("team-A", 5, -5, 0);
$team_data[] = array("team-B", 7, 3, 50);
$team_data[] = array("team-C", 8, 3, 50);
$team_data[] = array("team-D", 10, 4, 85);
$team_data[] = array("team-E", 10, 4, 90);
$team_data[] = array("team-F", 10, 5, 100);

// compare function
function team_comp($a, $b) {
 if ($a[1] != $b[1]) {
 return $b[1] - $a[1];
 } else if ($a[2] != $b[2]) {
 return $b[2] - $a[2];
 } else {
 return $b[3] - $a[3];
 }
}

usort($team_data, "team_comp");



データが、キーがチーム名で、成績の配列が値になっているような配列の場合には、たまたま arsort が使える。

<?php
// test data
$team_data["team-A"] = array(5, -5, 0);
$team_data["team-B"] = array(7, 3, 50);
$team_data["team-C"] = array(8, 3, 50);
$team_data["team-D"] = array(10, 4, 85);
$team_data["team-E"] = array(10, 4, 90);
$team_data["team-F"] = array(10, 5, 100);

arsort($team_data);



jsFiddle でやってみた結果です。
http://ideone.com/H2AbYz usort を使った場合
http://ideone.com/Jz2PEc arsort を使った場合



順位表が並べ替えの対象だと思うと、勝ち数、負け数など、並べ替えに関係のない値もデータに入っていると思うので、usort を使うのが良いんじゃないかと思います。

f:id:a-kuma3:20150522094132p:image
http://soccer.yahoo.co.jp/jleague/standings/j1
のようなのを対象にするとしたら、こんな感じで。

<?php

// 0: チーム名
// 1: 勝点
// 2: 試合数
// 3: 勝数
// 4: 引分数
// 5: 負数
// 6: 得点
// 7: 失点
// 8: 得失点差
$team_data[] = array("浦和レッズ", 27, 11, 8, 3, 0, 21, 9, 12);

 ...

// compare function
function team_comp($a, $b) {
 // 勝点
 if ($a[1] != $b[1]) {
 return $b[1] - $a[1];

 // 得失点差
 } else if ($a[8] != $b[8]) {
 return $b[8] - $a[8];

 // 総得点
 } else {
 return $b[6] - $a[6];
 }
}


usort($team_data, "team_comp");

khaieさんのコメント
ありがとうございました。 正確な動作はわかりませんが、期待する動きになってきました。 データベース知識がないため、元データはよく見る星取表をタブ区切りでチーム名、Aチームとのスコア、Bチームとのスコア、、、がチーム数分行になっているものです。 比較関数を使えば重み付け部分が必要なくなりますね。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ