2016年5月3日火曜日

順位付けMapを作る。(Java)


Javaで、よくやる順位付け(ランキング)、
TreeMapを使って順位を生成する関数を作ってみる。


スコアをリストで持っているとして、ここでは乱数でリストを用意。
List<Integer> list = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
    list.add(random.nextInt(10));
}
で、Mapを生成する関数を作った。
返されるMapはscoreをキーに値が順位になっています。 { score => rank, ... }
ascending: 昇順ならtrue、降順ならfalse
rankWithoutSkipping: 同一順位の後、順位をスキップさせたくないならtrue
public static Map<Integer, Integer> makeRankMap(Collection<Integer> scores, 
                                                boolean ascending, 
                                                boolean rankWithoutSkipping) 
{
    TreeMap<Integer, Integer> map = new TreeMap<>(ascending ? null : Collections.reverseOrder());
    for (int score : scores) {
        map.put(score, map.getOrDefault(score, 0) + 1);
    }

    if (rankWithoutSkipping) {
        int rank = 1;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            entry.setValue(rank++);
        }
        return map;
    }

    int rank = 1;
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
        rank += entry.setValue(rank);
    }
    return map;
}

最初にスコアをキーにしたTreeMapを作成する。
降順の場合はCollections.reverseOrder()をコンストラクタに渡すようにしています。
キーに対しての値には、同じスコアが何個あるかを一時的に記憶しておきます。

TreeMapなので、キーの値によって既に昇順または降順に保持されています。
rankWithoutSkipping:trueの場合は、単純に順番にランク付けしていくだけです。
rankWithoutSkipping:falseの場合は、同じスコアの所持数に応じてランク付けしていきます。

使う時は、scoreを使ってgetすれば、順位付けしたランクが取得できます。



rankWithoutSkipping: false で実行した例
Map<Integer, Integer> rankMap = makeRankMap(list, false, false);

list.sort((a, b) -> b - a);
for (int score : list) {
    System.out.printf("rank:%d, score:%d\n", rankMap.get(score), score);
}

/* --- output ---
rank:1, score:9
rank:1, score:9
rank:3, score:8
rank:4, score:7
rank:5, score:6
rank:6, score:5
rank:6, score:5
rank:8, score:3
rank:9, score:2
rank:9, score:2
------------------- */


rankWithoutSkipping: true で実行した例
Map<Integer, Integer> rankMap = makeRankMap(list, false, true);

list.sort((a, b) -> b - a);
for (int score : list) {
    System.out.printf("rank:%d, score:%d\n", rankMap.get(score), score);
}

/* --- output ---
rank:1, score:9
rank:1, score:9
rank:2, score:8
rank:3, score:7
rank:4, score:6
rank:5, score:5
rank:5, score:5
rank:6, score:3
rank:7, score:2
rank:7, score:2
------------------- */


0 件のコメント:

コメントを投稿