phpのkrsortについてです。

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

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

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

回答の条件
  • 1人1回まで
  • 13歳以上
  • 登録:2015/05/22 05:40:20
  • 終了:2015/05/22 17:44:45

ベストアンサー

id:a-kuma3 No.2

a-kuma3回答回数4537ベストアンサー獲得回数18882015/05/22 09:40:47

ポイント100pt

そもそも、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");
id:khaie

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

2015/05/22 17:43:03

その他の回答(1件)

id:TransFreeBSD No.1

TransFreeBSD回答回数665ベストアンサー獲得回数2672015/05/22 08:33:41

ポイント50pt

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からのアクセスは悪くなります。

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

他1件のコメントを見る
id:khaie

キーの意味がよくわかっていなかったようです。

2015/05/22 17:43:34
id:TransFreeBSD

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

2015/05/22 19:09:47
id:a-kuma3 No.2

a-kuma3回答回数4537ベストアンサー獲得回数18882015/05/22 09:40:47ここでベストアンサー

ポイント100pt

そもそも、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");
id:khaie

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

2015/05/22 17:43:03

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません