1. ホーム
  2. java

[解決済み] TreeMapの値によるソート

2022-03-13 21:20:57

質問

私は、デフォルトの自然な順序ではなく、値によってTreeMapを並べ替えることができるコンパレータを書きたいと思っています。

このようなことをやってみたのですが、何がいけなかったのかわかりません。

import java.util.*;

class treeMap {
    public static void main(String[] args) {
        System.out.println("the main");
        byValue cmp = new byValue();
        Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
        map.put("de",10);
        map.put("ab", 20);
        map.put("a",5);

        for (Map.Entry<String,Integer> pair: map.entrySet()) {
            System.out.println(pair.getKey()+":"+pair.getValue());
        }
    }
}

class byValue implements Comparator<Map.Entry<String,Integer>> {
    public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
        if (e1.getValue() < e2.getValue()){
            return 1;
        } else if (e1.getValue() == e2.getValue()) {
            return 0;
        } else {
            return -1;
        }
    }
}

私が聞きたいのは このような場合 Map.Entry はコンパレータに渡されますか?

どのように解決するのですか?

を持つことはできません。 TreeMap を無視することになるので、それ自体が値でソートされます。 SortedMap という仕様になっています。

A Map をさらに提供するものです。 トータルオーダー その キー .

しかし、外部コレクションを使用すると、常にソートすることができます。 Map.entrySet() は、キーや値、あるいはその組み合わせなど、どのような方法でもかまいません。

を返す汎用的なメソッドを紹介します。 SortedSetMap.Entry を指定すると Map であり、その値は Comparable :

static <K,V extends Comparable<? super V>>
SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
    SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
        new Comparator<Map.Entry<K,V>>() {
            @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                int res = e1.getValue().compareTo(e2.getValue());
                return res != 0 ? res : 1;
            }
        }
    );
    sortedEntries.addAll(map.entrySet());
    return sortedEntries;
}

これで、以下のようになります。

    Map<String,Integer> map = new TreeMap<String,Integer>();
    map.put("A", 3);
    map.put("B", 2);
    map.put("C", 1);   

    System.out.println(map);
    // prints "{A=3, B=2, C=1}"
    System.out.println(entriesSortedByValues(map));
    // prints "[C=1, B=2, A=3]"

のいずれかを変更しようとすると、おかしなことが起こることに注意してください。 SortedSet 自体、あるいは Map.Entry のような元の地図のquot;view"ではなくなってしまうからです。 entrySet() があります。

一般的に、マップのエントリーを値でソートする必要性は非典型的なものです。


注意事項 == に対して Integer

オリジナルのコンパレータが比較するのは Integer を使って == . これはほとんどの場合、間違っています。 ==Integer オペランドは参照等価であり、値の等価ではありません。

    System.out.println(new Integer(0) == new Integer(0)); // prints "false"!!!

関連する質問