###前提・実現したいこと
以下のような仕組みで最終順位を計算したいのですが、rubyでどう書くのが簡潔なのかで悩んでいます。力技で実現できるとは思うのですが、このメソッドを使う方が良いなど、何か簡潔な方法やアドバイスなどあれば教えてください。
####順位付け方法
- 複数の選手を複数の審査員が順位付けして、全ての情報を総合して順位を計算する
- 審査員は必ず奇数人数
審査員A | 審査員B | 審査員C | 審査員D | 審査員E | |
---|---|---|---|---|---|
Ken | 4 | 7 | 1 | 1 | 1 |
Shinji | 1 | 3 | 4 | 2 | 3 |
Taro | 3 | 2 | 2 | 4 | 4 |
Kazuya | 5 | 5 | 6 | 3 | 2 |
Shota | 7 | 4 | 3 | 5 | 5 |
Fumiya | 6 | 1 | 7 | 6 | 6 |
Ryu | 2 | 6 | 5 | 7 | 7 |
※審査員Aは、 Shinji → Ryu → Taro → Ken → Kazuya → Fumiya → Shota の順で順位付けしたイメージ。
- これをまずはソート
- | - | - | 中央値 | - | - |
---|---|---|---|---|---|
Ken | 1 | 1 | 1 | 4 | 7 |
Shinji | 1 | 2 | 3 | 3 | 4 |
Taro | 2 | 2 | 3 | 4 | 4 |
Kazuya | 2 | 3 | 5 | 5 | 6 |
Shota | 3 | 4 | 5 | 5 | 7 |
Fumiya | 1 | 6 | 6 | 6 | 7 |
Ryu | 2 | 5 | 6 | 7 | 7 |
- 最初の判定基準:中央値の小さい方が上位。この時点で Ken の1位が確定
- 中央値が同じ場合は、中央値以降で同じ数値をいくつ保持しているかで比較。Shinji と Taro は、中央値3をそれぞれ 2つ vs 1つとなるので、Shinji の方が上位
- 同様に Kazuya と Shota を比較すると、双方とも 中央値5を 2つずつ保持している。この場合は、中央値より手前の数値の総和が小さいものを上位とする。Kazuya は 5(=2+3)、Shota は 7(=3+4)となるので、Kazuya の方が上位
- 同様に Fumiya と Ryu を比較すると、中央値の保持数が 2つ vs 1つ となるので、Fumiya の方が上位
- なお、中央値、中央値の保持数、中央値より手間の総和比較も同値だった場合は、中央値より後の数値を順次比較していき、数値の小さい方が上位
- 全ての基準に照らし合わせて、全て同じ値となった場合は同率順位
####コードの前提条件
事前に取得できている情報は以下のようなハッシュ形式。
ruby
1pry> rank_hash 2=> {"Ken"=>[1, 1, 2, 3, 4], 3 "Shinji"=>[2, 2, 2, 3, 4], 4 "Taro"=>[1, 1, 4, 4, 5], 5 ...}
- キー : 選手名
- バリュー : その選手に付けられた順位の配列(ソート済)
####現状のコード(作りかけ)
コンソールで色々と動作確認しながら書いていっているため、関数分割したりなどは現時点では未考慮になります。
ruby
1# 中央値を取得するためのインデックス 2median_cnt = judge_num / 2 # 審査員の数(judge_num)は設定ファイルなどから取得済と思ってください 3 4judging_infos = [] 5rank_hash.each do |name, ranks| 6 # 中央値 7 median = ranks[median_cnt] 8 9 # 中央値以降の順位 10 ranks_latter_half = ranks.drop(median_cnt) 11 12 # 中央値が後半にいくつあるかをカウント 13 majority_cnt = ranks_latter_half.group_by(&:itself)[median].count 14 15 # 中央値より前の順位 16 ranks_first_half = ranks.take(median_cnt) 17 18 # 中央値より前の合計値 19 upper_sum = ranks_first_half.sum 20 21 # 算出した情報をまとめて配列に保持 22 judging_infos << [name, median, majority_cnt, upper_sum] 23end 24 25# 算出した情報を中央値でソート 26judging_infos.sort!{|a, b| a[1] <=> b[1]} 27 28# これ以降、上記までに取得した情報を使って処理すれば良いものと思いロジックを検討中 29 30# 先頭の要素を取得 31place, name_places = 1, {} 32judging_info = judging_infos.shift 33while(judging_infos.present?) do 34 median = judging_info[1] 35 36 # 中央値が異なるので順位確定 37 unless median == judging_infos[0][1] 38 name_places.store(judging_info[0], place) 39 place += 1 40 next 41 end 42 43 # 中央値が同じものを処理する 44 # このあたりの処理が while の多重ループになりそうで頭を悩ませ中 45 # 一通り組み終わった後でリファクタしても良いが、そもそもコードとしてイケてない感しか無い… 46 compare_infos = ... 47 while(中央値が同じ間) do 48 中央値が同じものを処理対象として抽出 49 end 50 51 中央値のカウント数でソート 52 53 while(取り出した情報数) do 54 ... 55 end 56end
回答4件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/03/04 16:21
2017/03/05 05:08