2

値の属性に基づいてJavaTreeMapをソートしたいと思います。具体的にはTreeMap<Integer, Hashset<Integer>>、のサイズに基づいて並べ替えたいと思いますHashset<Integer>。これを達成するために、私は次のことを行いました。

コンパレータクラス:

private static class ValueComparer implements Comparator<Integer> {
    private Map<Integer, HashSet<Integer>>  map = null;
    public ValueComparer (Map<Integer, HashSet<Integer>> map){
        super();
        this.map = map;
    }

@Override
    public int compare(Integer o1, Integer o2) {
        HashSet<Integer> h1 = map.get(o1);
        HashSet<Integer> h2 = map.get(o2);

        int compare = h2.size().compareTo(h1.size());

        if (compare == 0 && o1!=o2){
            return -1;
        }
        else {
            return compare;
        }
    }
}

使用例:

TreeMap<Integer, HashSet<Integer>> originalMap = new TreeMap<Integer, HashSet<Integer>>();

//load keys and values into map

ValueComparer comp = new ValueComparer(originalMap);
TreeMap<Integer, HashSet<Integer>> sortedMap = new TreeMap<Integer, HashSet<Integer>>(comp);
sortedMap.putAll(originalMap);

問題:

originalMap同じサイズの値が3つ以上含まれている場合、これは機能しません。その他の場合は、問題なく動作します。マップ内の3つ以上の値が同じサイズの場合、新しいソート済みマップの3番目の値はnullであり、アクセスしようとするとNullPointerExceptionがスローされます。

何が問題なのかわかりません。誰かが指摘できれば、Wouleはいいですね。

更新: 2つの値が同じサイズの場合に機能する例を次に示します。http://ideone.com/iFD9c 上記の例では、52〜54行目のコメントを外すと、このコードは失敗します。これが私の問題です。

4

6 に答える 6

6

更新:重複するキーが削除されないようにしたいという理由だけで、-1から戻ることはできません。ValueComparatorの契約を確認してくださいComparator.compare


を渡すと、エントリを配置するための(「新しい」)場所が計算Comparatorされます。(計算された)キーは、に複数回存在することはできませんTreeMapTreeMap


値のサイズで並べ替える場合orginalMapは、次のように実行できます。

public static void main(String[] args) throws Exception {

    TreeMap<Integer, HashSet<Integer>> originalMap = 
        new TreeMap<Integer, HashSet<Integer>>();

    originalMap.put(0, new HashSet<Integer>() {{ add(6); add(7); }});
    originalMap.put(1, new HashSet<Integer>() {{ add(6); }});
    originalMap.put(2, new HashSet<Integer>() {{ add(9); add(8); }});


    ArrayList<Map.Entry<Integer, HashSet<Integer>>> list = 
        new ArrayList<Map.Entry<Integer, HashSet<Integer>>>();
    list.addAll(originalMap.entrySet());

    Collections.sort(list, new Comparator<Map.Entry<Integer,HashSet<Integer>>>(){
        public int compare(Map.Entry<Integer, HashSet<Integer>> o1,
                           Map.Entry<Integer, HashSet<Integer>> o2) {

            Integer size1 = (Integer) o1.getValue().size();
            Integer size2 = (Integer) o2.getValue().size();
            return size2.compareTo(size1);
        }
    });

    System.out.println(list);
}
于 2011-10-06T10:36:26.610 に答える
1

TreeMapをキーのみで並べ替えることができます。StackOverflowExceptionが発生するため、値順にツリーマップを作成する方法はありません。

考えてみてください。ツリーから要素を取得するには、比較を実行する必要がありますが、比較を実行するには、要素を取得する必要があります。

他のコレクションで並べ替えるか、Treeを使用する必要があります。また、(エントリ値からの)整数をエントリキーにカプセル化し、キーから取得した整数を使用してコンパレータを定義する必要があります。

于 2011-10-06T10:57:36.283 に答える
1

コンパレータはコンパレータコントラクトを尊重しません。の場合compare(o1, o2) < 0は、compare(o2, o1)である必要があります> 0。両方のサイズが同じで整数が同一でない場合に、要素を比較する決定論的な方法を見つける必要があります。System.identityHashCode()この場合、整数のを使用してそれらを比較することができます。

そうは言っても、そのようなマップで何ができるのか、本当に疑問に思います。新しい整数を作成してマップから値を取得するためにそれらを使用することはできず、マップが保持するセットを変更することもできません。

補足:コンパレータコードサンプルはmap、とを使用dataして同じマップを参照します。

于 2011-10-06T10:38:23.630 に答える
1

コンパレータロジック(設定されたサイズが等しいがキーが異なる場合に-1を返す理由はわかりません)は、を呼び出したときにマップ自体が返すものに影響を与えないはずですget(key)

初期マップにnull値を挿入していないことを確信していますか?このコードはどのように見えますか?

于 2011-10-06T10:38:40.690 に答える
0

Setで0を返すコンパレータを使用できないと仮定すると、これは機能する可能性があります。すべての要素をに追加してoriginalMap.entrySet()から、を使用してArrayList並べ替え、必要に応じて変更します。ArrayListValueComparerreturn 0

ArrayList次に、並べ替えられたすべてのエントリをに追加しますLinkedHashMap

于 2011-10-06T10:50:53.457 に答える
0

元のポスターと同じような問題がありました。値で並べ替えたいTreeMapがありました。でも、値を見てコンパレータを作ってみると、JBが話していたコンパレータが壊れて困っていました。カスタムコンパレータを使用しても、契約を守ることができました。私が見ていた値が等しいとき、私はキーの比較に戻りました。値が等しい場合、順序は気にしませんでした。

    public int compare(String a, String b) {
    if(base.get(a)[0] == base.get(b)[0]){ //need to handle when they are equal
        return a.compareTo(b);
    }else if (base.get(a)[0] < base.get(b)[0]) {
        return -1;
    } else {
        return 1;
    } // returning 0 would merge keys
于 2013-09-19T12:38:12.673 に答える