Javaで順位付けする方法
どうやって順位付けを行うのか、考えたことはありますか?
結構コードを書いていて、最初はぐちゃぐちゃしたものになってしまっていたので、自分で試してみた方法を上げてみたいと思います。
環境
- java14
使用させていただいたデータ
今回はワインの評価データのポイントが高い上位30番以内のデータを出力します。
同率順位も可能性としてはあるので、この場合は30個を超えることもあります。
例えば、ポイントが2,2,3,3,5,5,8,8,8,9,12であり、この上位3位まで出力する場合、
1位 12
2位 9
3位 8
3位 8
3位 8
となります。
実際書いたコード
for文で行ったりする方法も考えられると思います。
また、sort部分はクイックソートなどを使っても効率化される場合もあると思います。
今回私が意識したのは、「可読性」です。できるだけシンプルかつ、読みやすいコードです。
どうしてもstream
を使って行いたかったので、今回はMap
を使用することにしました。
色々やり方はあるとは思いますが、今回はKeyをポイント、そしてEntityをワインのモデルのList
とすることにします。
それが以下のコードです。
public static Map<Integer, List<WinModel>> getSortedWinModelMapByWinModelList(List<WinModel> winModelList) {
return winModelList.stream()
.collect(Collectors.groupingBy(WinModel::getPoints))
.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
コードの解説です。
csvファイルで読み取ったデータは全てワインのモデルに変換し、List
に格納しています。
そのList
が、上記のメソッドの引数であるwinModelList
です。
Keyをポイント、そしてEntityをワインのモデルのList
とするときには、.collect(Collectors.groupingBy())
を使います。groupingBy()
の中に、まとめたいもののキーを記述します。今回はポイントでグルーピングしたいので、下記のようなコードになりました。
.collect(Collectors.groupingBy(WinModel::getPoints))
さらに、今回はポイント(キー)で降順にソートしたいため、以下のように記述します。
.sorted(Collections.reverseOrder(Map.Entry.comparingByKey()))
なお、ソートのときには昇順のときにはnaturalOrder()
を使います。
ソートしたあと、きちんとMap
に戻す必要があるので、
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
あとはこの関数に、先程のMapと何番目まで出力するのか決めた数字を引数で渡し、出力してあげます。
public static void printResult(Map<Integer, List<WinModel>> winMap, int num) {
int rank = 1;
for (Integer key : winMap.keySet()) {
if (rank > num) {
break;
}
for (WinModel winModel : winMap.get(key)){
System.out.println(rank + " " + winModel.getPoints() + " " + winModel.getDesignation());
}
rank += winMap.get(key).size();
}
}
30番目までの出力は、
1 100 En Chamberlin Vineyard
1 100 Rare
・・・(中略)・・・
23 99 Madonna delle Grazie
23 99 Cailloux Vineyard
23 99 Royal City Stoneridge Vineyard
・・・(中略)・・・
となりました。うまく行きました。
最後に
ソートだけでも結構考えさせられることがあるなと改めて感じました。
プログラミングは興味深いですね。