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

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

ただいまの
回答率

90.53%

  • C++

    3432questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • アルゴリズム

    408questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

標準的な順位付け

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,167

majiponi

score 822

(カードゲームのログの解析プログラム中、)スコアから順位付けをするコードを書いています。書けたことは書けたのですが、かなり複雑になってしまい、もっと簡単な方法、それこそ、標準STLが用意してくれた方法はないかと調べてみたのですが、自分では見つけられなかったので、御存知の方がいらっしゃれば御教授願います。

自分が書いたコードの概要

構造体 R{
整数型 スコア,順位,プレイヤーID;
}
R データ[人数];
人数分、データ[プレイヤーID].スコアをセット;
人数分、データ[プレイヤーID].プレイヤーIDをセット;
std::sortでスコア順にデータをソート;
人数分、データ[i].順位をセット;
std::sortでプレイヤーID順にデータをソート;

現在検討中のコード1 (Stack Overflowからヒントをもらった)

構造体 R{
整数型 スコア,順位;
}
R データ[人数];
R* 順番[人数];

人数分、データ[プレイヤーID].スコアをセット;
人数分、順番[プレイヤーID]にデータ[人数]のアドレスをセット;
std::sortでスコア順に順番をソート;
人数分、順番[i]->順位をセット;

現在検討中のコード2

構造体 R{
整数型 スコア,順位;
}
R データ[人数];

人数分、データ[プレイヤーID].スコアをセット;
人数分、順番[プレイヤーID]に、std::count_ifで自分のスコアより大きいスコアを持つ人数+1をセット;


ちなみにプレイヤー数は4人以下です。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+3

こんなんでどぉぢゃろ

#include <algorithm>
#include <iostream>
#include <random>

using namespace std;

struct R {
  int score;
  int rank;
  int id;
};

int main() {
  const int N = 100;
  R data[N];

  mt19937 gen;
  uniform_int_distribution<> dist(0,30);
  auto rnd = [&]() { return dist(gen); };

  // テキトーな乱数で埋める
  for (int i = 0; i < N; ++i) {
    data[i].id = i;
    data[i].score = rnd();
  }

  // scoreでソートする
  auto score_less = [](const R& x, const R& y) { return x.score > y.score; };
  sort(begin(data), end(data), score_less);

  // 順位づけ
  for (int i = 0; i < N; ++i) {
    data[i].rank = static_cast<int>(distance(begin(data), lower_bound(begin(data), end(data), data[i], score_less)))+1;
  }

  // できたかな?
  cout << "id\trank\tscore\n";
  for ( auto item : data ) {
    cout << item.id << '\t' << item.rank << '\t' << item.score << endl;
  }

}

実行結果はこんな↓

id      rank    score
66      1       30
0       2       29
2       2       29
32      2       29
7       2       29
44      6       28
42      6       28
72      6       28
21      6       28
89      6       28
5       11      27
45      12      26
69      12      26
50      12      26
41      12      26
98      16      25
74      16      25

人数分、順番[プレイヤーID]に、自分のスコアより大きいスコアを持つ人数+1をセット
なら上記コードの順位づけの部分を

  for_each(begin(data), end(data), 
           [&](R& item) {
             item.rank = static_cast<int>(count_if(begin(data), end(data), 
                             [&](const R& t) { return t.score > item.score; }));
           });

この場合実行結果は:

id      rank    score
0       1       29
1       44      15
2       1       29
3       52      13
4       96      0
5       10      27
6       92      1
7       1       29
8       92      1
9       25      21
10      52      13
11      22      22
12      79      5
13      75      6
...

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/25 22:08

    ID順に表示したいんですよね…
    それで、2回ソートってなんか煩雑だし、1回にできないかな、というのがテーマです。言葉足らずで申し訳ないorz

    キャンセル

  • 2017/03/25 22:10 編集

    キーの異なるふたつのソートをどうやって一回で済ますんです?
    得点順で、同じ得点ならIDの若い順 とかならともかく。
    ※ てかソートすんのにsort(...)の一行を追加するのが煩雑?

    キャンセル

  • 2017/03/27 17:33

    師匠から、「アルゴリズムのオーダー改善は必要なのか?」と痛烈な指摘を受けたので、一番分かりやすいと思ったeprstemeさんの案を採用します。
    ※実際はtuple使っていたので、sortの1文だけでラムダ関数込みで5行近く書いていたのですよ…。質問は要約です。

    キャンセル

  • 2017/03/27 17:37

    おや?
    私の回答は、ソートは事実上1回だけですよ。
    スコアとプレイヤーIDのペアをスコアでソートして、結果を枚挙しつつ順位設定です。2回ソートするよりは速い場合が多い筈です。

    キャンセル

  • 2017/03/28 00:43

    実は…何が起きているのかよく分からなかったのです、multimap使ったことがなくて…。動きが正しいのは検証して分かった、でもなんで?
    一晩寝かせてようやく「ああ、こういうことなのか」と理解できました。なので、一目で理解できたほうにBAしてしまいました…すみませぬorz

    キャンセル

  • 2017/03/28 01:37

    いいえ。こちらこそ、うまく伝えられなくてすいません。

    キャンセル

+2

こんにちは。

std::multimapを使う案です。
もっとスマートな方法がありそうな気もしますが、ソートと言えばmapしか思いつかない...(setは面倒ですし)

構造体 R
{
    整数型 スコア,順位;
};
R データ[人数];
{
    std::multimap<整数型, 整数型> m;
    std::pair<const 整数型, 整数型>(スコア, プレイヤーID)を人数分mへemplace;
    整数型 i=0;
    for (auto&& プレイヤー : m)
    {
        データ[プレイヤー.プレイヤーID].順位=++i;
        データ[プレイヤー.プレイヤーID].スコア=プレイヤー.スコア;
    }
}


順位は同じスコアの時の対処が必要です。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • C++

    3432questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • アルゴリズム

    408questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。