2
2

More than 1 year has passed since last update.

Javaで重複した順位付けをする方法

Posted at

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
・・・(中略)・・・

となりました。うまく行きました。

最後に

ソートだけでも結構考えさせられることがあるなと改めて感じました。
プログラミングは興味深いですね。

2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2